Skip to content

Security Standards and Compliance

Security standards for AI-assisted development rest on four enforceable layers: a data boundary each tool exposes as a setting (privacy mode, managed deny rules, sandbox), rules files backed by those deny lists, the audit surfaces the tools actually emit, and CI gates that block unreviewed migrations, leaked secrets, and OWASP findings. Together they turn SOC 2, GDPR, and HIPAA evidence into a passing check.

Your security team just put the AI rollout on hold, and the questions are reasonable: where does our source code go, can a developer paste a customer’s PII into a prompt, and can you prove to a SOC 2 auditor exactly who ran what? Three weeks out from the Type II audit, the assessor also wants evidence that AI-generated code is reviewed before it ships and that the MCP servers your team installed last sprint are not quietly exfiltrating files. Meanwhile developers are merging agent-authored PRs at three times last year’s pace.

Generic “use clear prompts” advice answers none of that. What follows is the concrete, enforceable set: the settings you flip, the configs you commit, the audit surfaces these tools actually ship, and the scanners and policies you wire into CI — so compliance is a passing check rather than a quarterly fire drill, and the controls keep up without becoming the bottleneck everyone routes around.

What this compliance-gating setup gives you

Section titled “What this compliance-gating setup gives you”
  • The exact privacy and data-retention setting to enforce in Cursor, Claude Code, and Codex so source code is not retained or trained on
  • A committed, machine-enforced policy file per tool that blocks .env reads, dangerous shell, and unapproved MCP servers — not a wiki page people ignore
  • The real audit and telemetry configuration for each tool, with no invented settings keys, mapped to SOC 2, GDPR, and HIPAA control families
  • A working MCP supply-chain scan using Snyk Agent Scan (formerly Invariant MCP-Scan) wired into all three tools
  • A PreToolUse hook and pre-commit setup that scans diffs for secrets and PII before anything leaves the machine, using real OSS (gitleaks, detect-secrets, trivy)
  • Copy-paste prompts that produce runnable artifacts: a Semgrep ruleset, an OWASP Top 10:2025 review, a CODEOWNERS-gated PR template, SOC 2 CC7.1 audit middleware, and an Open Policy Agent gate that blocks unreviewed AI-generated migrations
  • A failure-modes section covering the gotchas auditors and red teams actually find

Where AI tooling touches your compliance boundary

Section titled “Where AI tooling touches your compliance boundary”

Three surfaces matter for an audit:

  • Data egress. Your prompts contain source code and sometimes secrets. For SOC 2 confidentiality and HIPAA, you need a documented zero-retention posture with each vendor. Cursor’s Privacy Mode and Enterprise plan guarantee zero data retention (see trust.cursor.com); Anthropic and OpenAI offer the same for API and enterprise tiers. Document which mode each tool runs in — that document is the control evidence.
  • Audit trail. You need to show who ran what. Each tool exposes a different mechanism. None of them has a magic audit_logging: true flag — the real surfaces are OpenTelemetry, shell-command wrapping, and platform admin logs.
  • Supply chain. MCP servers run with your tools’ privileges. In Equixly’s 2025 assessment of popular open-source MCP server implementations, 43% contained command-injection flaws, 30% allowed unrestricted URL fetches, and 22% leaked files outside their intended directories. Treat every MCP server like an unvetted dependency.

Step 1: lock the data boundary in each tool

Section titled “Step 1: lock the data boundary in each tool”

These controls differ meaningfully per tool, so configure each one. The goal is identical: prevent source and secrets from being retained, and stop sensitive files from ever entering context.

Enforce Privacy Mode at the team level so individuals cannot turn it off, then keep sensitive files out of indexing and context with .cursorignore.

  1. Team dashboard -> Settings -> enable Privacy Mode and toggle Enforce (members can no longer disable it). Privacy Mode is on by default for Enterprise and gives you ZDR with all model providers.
  2. On corporate devices, deploy the Allowed Team IDs MDM policy so users cannot sign into a personal account that lacks Privacy Mode.
  3. Commit a .cursorignore so secrets and infra never get indexed or sent as context:
# .cursorignore — never index or send to models
.env
.env.*
**/secrets/**
**/*.pem
**/*.key
terraform.tfstate*
**/credentials.json

For regulated workloads, ask sales to enable CMEK (customer-managed encryption keys) so embeddings and any Cloud Agent data are encrypted with your key. If your policy forbids storing code at all, simply do not enable Cloud Agents — every other Cursor feature still works. Cursor Business and Enterprise carry SOC 2 Type II attestations, which is what you attach to the vendor-management file.

Step 2: rules that guide, deny lists that enforce

Section titled “Step 2: rules that guide, deny lists that enforce”

The legacy single-file .cursorrules is deprecated. Use Cursor Project Rules (.cursor/rules/*.mdc), Claude Code’s CLAUDE.md plus committed project settings, and Codex’s AGENTS.md. A rules file is guidance the model usually follows; the deny lists from Step 1 are what actually enforce it. Use both.

Create .cursor/rules/security.mdc. The frontmatter alwaysApply: true injects it into every session:

---
description: "Security & data-handling rules"
alwaysApply: true
---
- Privacy Mode must stay enabled; never sign in with a personal account.
- Never write API keys, passwords, tokens, or connection strings into code. Read them from `process.env`.
- Never put customer PII (names, emails, SSNs, MRNs) in fixtures, logs, or prompts. Use `@faker-js/faker` for test data.
- When discussing a schema with PII columns, use anonymized column names.
- Reference `.env.example` for environment variable names, never `.env`.
- Mark AI-assisted code with a `// AI-assisted` comment so review and CODEOWNERS can track it.
- Redact secrets before logging; encrypt sensitive data at rest and in transit.

Guidance about handling secrets is the floor. The rule file earns its keep when it encodes your standards, so that generated code is secure by default rather than plausible by default:

// .cursor/rules/security.mdc, CLAUDE.md, or AGENTS.md — standards section
SECURITY CODING STANDARDS:
Authentication:
- All API endpoints must use the authMiddleware from /src/middleware/auth.ts
- JWT tokens expire after 15 minutes, refresh tokens after 7 days
- Password hashing uses bcrypt with cost factor 12
Input Validation:
- All request bodies validated with Zod schemas before processing
- File uploads limited to 10MB, allowed types: jpg, png, pdf
- URL parameters must be validated as UUIDs where applicable
Database:
- ALL queries must use parameterized statements (Drizzle ORM or prepared statements)
- Never construct SQL strings with string concatenation
- Database connections use least-privilege service accounts
Output:
- All HTML output must be escaped (handled by React/template engine)
- API responses must not include internal error details in production
- Set Content-Security-Policy, X-Frame-Options, X-Content-Type-Options headers

Step 3: turn on the audit evidence each tool actually emits

Section titled “Step 3: turn on the audit evidence each tool actually emits”

This is the part most teams get wrong by pasting in config keys that do not exist. Here is what each tool actually supports.

Claude Code has no audit_logging setting. Observability is OpenTelemetry, and command-level auditing is a shell prefix. Enable both in ~/.claude/settings.json (managed settings on a controlled host for enterprise):

{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel-collector.internal:4317",
"CLAUDE_CODE_SHELL_PREFIX": "/usr/local/bin/audit-logger.sh"
}
}

CLAUDE_CODE_ENABLE_TELEMETRY=1 streams metrics and logs to your collector (then to your SIEM); CLAUDE_CODE_SHELL_PREFIX wraps every Bash command so audit-logger.sh <command> records it. That command log is your SOC 2 access/activity evidence.

Mapping SOC 2, GDPR, and HIPAA to those surfaces

Section titled “Mapping SOC 2, GDPR, and HIPAA to those surfaces”

Auditors do not accept “we trust developers.” Each surface above answers a specific control family:

  1. SOC 2 (CC6 access, CC7.1 detection). Pull access and usage logs from each tool’s admin surface: Cursor’s Admin API and team analytics, Claude Code via Claude for Enterprise (SSO, RBAC, compliance API), and the Codex Compliance API. For your own services, generate the CC7.1 audit-logging middleware with the prompt below.

  2. GDPR (data minimization, right to erasure). Keep PII out of prompts entirely — .cursorignore, permissions.deny, and the sandbox from Step 1 handle that. For erasure, the Codex Compliance API and the Cursor and Anthropic enterprise exports let you locate and account for any record tied to a user. Never use production data as test fixtures; generate synthetic data instead.

  3. HIPAA (PHI handling). Never send Protected Health Information to a model without a signed BAA covering that specific surface. Default to synthetic patients and redact PHI before it reaches a prompt.

Generate synthetic test data with the maintained @faker-js/faker (the old standalone faker package is deprecated and its faker.datatype.* API no longer exists):

import { faker } from '@faker-js/faker';
export function syntheticPatient() {
return {
id: faker.string.uuid(),
name: faker.person.fullName(),
dob: faker.date.past({ years: 80 }),
mrn: `TEST-${faker.number.int({ min: 100000, max: 999999 })}`,
conditions: ['Synthetic Condition A', 'Synthetic Condition B'],
};
}

Step 4: scan MCP servers before you trust them

Section titled “Step 4: scan MCP servers before you trust them”

Before any MCP server reaches a developer’s machine, scan it. The tool to use is Snyk Agent Scan (the former Invariant Labs MCP-Scan, now maintained by Snyk). It runs through uvx — it is a Python tool, so do not npm install it.

  1. Scan a candidate server’s config (or your whole mcp.json) for tool-poisoning, prompt-injection, and toxic-flow patterns:

    Terminal window
    uvx snyk-agent-scan@latest ~/.cursor/mcp.json

    The legacy entrypoint uvx mcp-scan@latest still works — it is now a redirect that installs snyk-agent-scan and forwards the CLI.

  2. Read the findings. A flagged server might show an unrestricted fetch tool that accepts arbitrary URLs, or a tool description containing hidden instructions (a tool-poisoning attack). Do not install it until that is resolved.

  3. Register the scanner itself as an MCP server so the agent can re-scan on demand:

Add it in Settings → MCP → Add Server, or edit ~/.cursor/mcp.json directly so the config is reviewable in version control:

{
"mcpServers": {
"security-analyzer": {
"command": "uvx",
"args": ["snyk-agent-scan"],
"env": { "SNYK_TOKEN": "${SNYK_TOKEN}" }
}
}
}

Only SNYK_TOKEN (for authenticated scans) is consumed — do not invent SECURITY_SCAN_MODE or SEMGREP_APP_TOKEN here. Run Semgrep as its own step rather than as env on the scanner.

Step 5: block secrets and PII before they leave the machine

Section titled “Step 5: block secrets and PII before they leave the machine”

Use real, maintained scanners — not a hand-rolled regex class. gitleaks (Go binary) and detect-secrets (pip install detect-secrets) catch credentials; trivy catches vulnerable dependencies and misconfiguration. Wire them in two places: a Claude Code PreToolUse hook that blocks a commit the agent is about to run, and CI as the backstop.

The hook is where the three tools diverge — Claude Code can block a tool call mid-flight; Cursor and Codex rely on pre-commit plus CI.

Cursor has no commit-blocking hook, so enforce at the git layer with a pre-commit config that every clone inherits:

.pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
hooks:
- id: gitleaks
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']

Run pre-commit install once per clone (or enforce it via your repo bootstrap). Now any commit — AI-assisted or not — is scanned before it lands.

Prompts that produce runnable artifacts, not documents

Section titled “Prompts that produce runnable artifacts, not documents”

The point of AI here is a shippable artifact — a ruleset, a fix, a policy file — not a Word doc describing one. Anchor prompts to a concrete stack so the output runs.

The Semgrep ruleset is the standing gate. For a full sweep of one module against the current OWASP list, ask for the review directly:

For a single pull request, the useful output is a verdict a reviewer can act on, not a checklist of categories:

The same discipline turns the quarterly compliance checklist into a repeatable pass:

Run any of these across tools — the workflow is identical; only the entry point differs. In Cursor, open the diff and invoke Agent mode on it, or hand it to a Background Agent on every PR. In Claude Code, run claude -p "<prompt>" on the branch so it reads the working tree, or wire it into a hook. With Codex, hand it the PR via the GitHub integration or codex exec in CI. Pin the model: use Claude Fable 5 for the highest-stakes reviews, Opus 5 for lower-cost premium reasoning, or the appropriate GPT-5.6 Sol/Terra/Luna tier in ChatGPT Codex. See model comparison for the full tier breakdown.

Audit evidence is strongest when it is automatic. Keep the hard gate deterministic and let the AI review advise, exactly as you would for any scanner.

The deterministic backstop is identical regardless of which tool wrote the code:

.github/workflows/security-scan.yml
name: Security Scan
on: [pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with: { fetch-depth: 0 }
- name: Secret scan
uses: gitleaks/gitleaks-action@v2
- name: Dependency & misconfig scan
uses: aquasecurity/trivy-action@v0.36.0
with: { scan-type: 'fs', severity: 'HIGH,CRITICAL', exit-code: '1' }
- name: AI-attribution check
run: |
count=$(git diff --name-only origin/${{ github.base_ref }}... \
| xargs grep -l "AI-assisted\|AI-generated" 2>/dev/null | wc -l)
if [ "$count" -eq 0 ]; then
echo "::warning::No AI-assisted attribution found in changed files"
fi

The AI review runs alongside it. Note how the gate is built: claude -p returns the model’s text response, not a severity-based exit code, so with --output-format json the answer lands in .result and a jq -e step is what fails the job:

.github/workflows/security-review.yml
security-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: AI Security Review
run: |
claude -p --output-format json "Review the git diff for security issues:
$(git diff origin/main...HEAD)
Check for:
1. SQL injection vulnerabilities
2. Missing authentication/authorization
3. Hardcoded secrets or credentials
4. Unvalidated user input
5. Insecure cryptographic operations
6. Missing rate limiting on new endpoints
Return ONLY JSON: {\"issues\": [{\"severity\", \"file\", \"line\", \"description\", \"fix\"}]}" \
| jq -e '.result | fromjson | all(.issues[]; .severity != "Critical" and .severity != "High")'

With Codex, the equivalent is an automation triggered by PR events, which posts findings back as a review instead of failing a step:

When a PR is opened, perform a security review:
1. Analyze all changed files for OWASP Top 10:2025 vulnerabilities
2. Check new dependencies against known vulnerability databases
3. Verify authentication is required on all new endpoints
4. Confirm input validation exists for all new user-facing parameters
5. Post findings as a PR review comment with inline annotations

The highest-leverage gate for AI-assisted teams is the one nobody builds by hand: blocking unreviewed schema changes. The migrations an agent generates are exactly where a confused-deputy mistake becomes a data-exposure incident.

The job’s pass/fail history is your continuous-compliance evidence — point the auditor at the Actions log instead of assembling a spreadsheet by hand. That is also the answer to “our audits take just as long as before”: run the checks per PR and the quarterly audit becomes a formality.

When enterprise AI security controls break down

Section titled “When enterprise AI security controls break down”
  • “Telemetry is on but the SIEM is empty.” CLAUDE_CODE_ENABLE_TELEMETRY=1 must be set before the OTEL exporter variables take effect, and the collector endpoint must be reachable from the developer’s host. Test with a local collector first; a blocked egress firewall silently drops the data.
  • uvx snyk-agent-scan reports nothing on a server you suspect. Static scans miss runtime behavior, and an over-broad MCP server can read the very files your deny list protects. Pair the scan with the sandbox controls above (no network, no filesystem scope), use deniedMcpServers / allowedMcpServers in managed settings, and watch the server’s actual tool calls — a clean scan is necessary, not sufficient.
  • The secret scanner blocks every commit. High-entropy test fixtures and example keys trip gitleaks and detect-secrets. Generate a baseline (detect-secrets scan > .secrets.baseline) and commit it, or add a scoped .gitleaksignore — never disable the scan entirely.
  • Redaction mangles legitimate prompts. Aggressive regex redaction turns user@example.com in a code sample into [REDACTED] and breaks the agent’s context. Redact in the diff and commit path, not in the prompt a developer is actively writing; prefer keeping PII out (ignore files) over scrubbing it after the fact.
  • The Rego gate blocks legitimate hotfixes. Build the escape hatch into the policy itself (the MIGRATION-RISK: accepted by line), not an admin override. An override that bypasses the control is an audit finding; a documented, labeled exception is the control working.
  • A developer bypasses the policy. A personal account or --dangerously-skip-permissions makes your committed rules irrelevant. This is why Step 1 matters: enforce Privacy Mode plus Allowed Team IDs (Cursor), disableBypassPermissionsMode plus managed settings (Claude Code), and RBAC (Codex) at the org level, not the repo level.
  • Cursor “audit settings” do not appear. They do not exist at the user level. If you need per-developer audit, you need the Enterprise plan’s admin surface plus host-level command logging — there is no client-side JSON for it.
  • An agent leaks a secret into a prompt. This is a data-egress incident, not a code bug. The UserPromptSubmit hook and the Read(./.env*) deny rules prevent it at the source; treat any breach as reportable under your incident-response plan.
  • PHI slips through because “ZDR” was assumed to be a BAA. Zero Data Retention prevents training and storage; it is not a Business Associate Agreement. No BAA, no PHI — full stop.
  • The security team will not approve AI tools at all. Bring the vendor’s SOC 2 report, the data processing agreement, and the zero-retention terms to the meeting rather than arguing from benefit. Enterprise plans provide contractual guarantees, and where absolute isolation is required, a local model keeps code on the machine.
  • Every team encodes security requirements differently. Centralize the rule content from Step 2 in one shared repository and distribute it — a monorepo package or a Git submodule — so the standards drift in one place, not twelve.

Where to go next with security and compliance

Section titled “Where to go next with security and compliance”