Enterprise Security & Compliance Workflows
Your security team just put the AI rollout on hold. 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 SOC2 auditor exactly who ran what? Generic “use clear prompts” advice does not answer any of that. This guide shows the concrete, enforceable controls each of the three tools actually ships — the settings you flip, the configs you commit, and the scanners you wire into CI — so you can clear the review and turn the rollout back on.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- 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
.envreads, dangerous shell, and unapproved MCP servers — not a wiki page people ignore. - A
PreToolUsehook 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 to generate a CODEOWNERS-gated review checklist, a secret/PII diff scanner, and SOC2 CC7.1 audit middleware for Express + Postgres.
- A mapping from SOC2 / GDPR / HIPAA controls to the audit surface each tool exposes (Cursor Admin API, Claude for Enterprise compliance API, Codex Compliance API).
Step 1: Enforce data protection at the tool level
Section titled “Step 1: Enforce data protection at the tool level”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.
- 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.
- On corporate devices, deploy the Allowed Team IDs MDM policy so users cannot sign into a personal account that lacks Privacy Mode.
- Commit a
.cursorignoreso secrets and infra never get indexed or sent as context:
# .cursorignore — never index or send to models.env.env.***/secrets/****/*.pem**/*.keyterraform.tfstate***/credentials.jsonFor 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.
Ship a managed settings file that IT deploys system-wide. Users and projects cannot override it, so this is your hard floor.
managed-settings.json lives at /Library/Application Support/ClaudeCode/ (macOS), /etc/claude-code/ (Linux/WSL), or C:\Program Files\ClaudeCode\ (Windows):
{ "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Read(./**/*.pem)", "Bash(curl:*)", "WebFetch" ] }, "allowManagedPermissionRulesOnly": true, "disableBypassPermissionsMode": "disable", "deniedMcpServers": [{ "serverName": "filesystem" }]}disableBypassPermissionsMode: "disable" kills the --dangerously-skip-permissions escape hatch. allowManagedPermissionRulesOnly ignores any allow/ask/deny rules a developer adds locally. deniedMcpServers blocks risky servers org-wide. Authenticate through Claude for Enterprise for SSO, RBAC, and the compliance API.
Lock the agent down with sandbox_mode and approval_policy, and split local vs cloud access in ChatGPT Enterprise.
In ~/.codex/config.toml (or push it via your team config):
# Read-only by default; agent must ask before writing or running anything riskysandbox_mode = "read-only"approval_policy = "on-request"
[sandbox_workspace_write]network_access = falseSandbox values are read-only, workspace-write, and danger-full-access — never danger-full-access on a developer laptop touching a real repo. In Workspace Settings -> Settings and Permissions, use RBAC to enable Codex Local (app/CLI/IDE, runs in the on-device sandbox) and Codex Cloud (hosted containers) for different groups. ChatGPT Enterprise gives ZDR for the CLI and IDE plus AES-256 at rest and TLS 1.2+ in transit.
Step 2: Replace the rules file with an enforced policy
Section titled “Step 2: Replace the rules file with an enforced policy”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---
- 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.- 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.Put the same rules in CLAUDE.md at the repo root (auto-loaded as memory), and commit team permission rules in .claude/settings.json:
{ "permissions": { "deny": ["Read(./.env)", "Read(./secrets/**)"], "ask": ["Bash(git push:*)"] }}CLAUDE.md steers the model; the committed deny/ask rules enforce the hard edges for everyone on the repo.
Codex reads AGENTS.md from the repo root. Use the same content as the Cursor rule above — the format is plain Markdown and the guidance is identical across tools. Pair it with the sandbox_mode from Step 1 so the rules are backed by an actual sandbox, not just intent.
Step 3: Scan diffs for secrets and PII before they leave the machine
Section titled “Step 3: Scan diffs for 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 misconfig. Wire them in two places: a Claude Code PreToolUse hook (blocks a commit the agent is about to run) and CI (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 + CI.
Cursor has no commit-blocking hook, so enforce at the git layer with a pre-commit config that every clone inherits:
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.
Add a PreToolUse hook that scans the staged diff before the agent is allowed to run git commit. In .claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": ".claude/hooks/scan-secrets.sh" }] } ] }}.claude/hooks/scan-secrets.sh reads the tool input on stdin and denies the commit if gitleaks finds anything:
#!/usr/bin/env bashcmd=$(jq -r '.tool_input.command // ""')case "$cmd" in *"git commit"*) if ! gitleaks git --staged --no-banner; then echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"gitleaks found a secret in the staged diff"}}' exit 0 fi ;;esacexit 0The agent literally cannot commit a secret — the hook returns permissionDecision: "deny" and Claude Code aborts the tool call.
Codex respects the pre-commit hooks above when it runs git commit inside the sandbox, so install them the same way. For an extra gate, keep Codex at approval_policy = "on-request" so it pauses for human approval before any commit or push, giving you a chance to eyeball the diff.
The CI backstop is identical regardless of which tool wrote the code:
name: Security Scanon: [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" fiStep 4: Map compliance controls to each tool’s audit surface
Section titled “Step 4: Map compliance controls to each tool’s audit surface”Auditors do not accept “we trust developers.” Each tool exposes an audit and access surface you can point a SOC2 / GDPR / HIPAA assessment at.
-
SOC2 (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 Codex’s Compliance API, which exports prompt text, responses, user, timestamp, model, and token usage straight into your SIEM/eDiscovery pipeline. For your own services, generate the CC7.1 audit-logging middleware (prompt below).
-
GDPR (data minimization, right to erasure). Keep PII out of prompts entirely —
.cursorignore/permissions.deny/ sandbox from Step 1 handle that. For erasure, the Codex Compliance API and Cursor/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. -
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'], };}When This Breaks
Section titled “When This Breaks”- The secret scanner blocks every commit (false positives). High-entropy test fixtures and example keys trip
gitleaks/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.comin a code sample into[REDACTED]and breaks the agent’s context. Redact in the diff/commit path, not in the prompt the developer is actively writing; prefer keeping PII out (ignore files) over scrubbing it after the fact. - A developer bypasses the policy. If someone uses a personal account or
--dangerously-skip-permissions, your committed rules do nothing. This is why Step 1 matters: enforce Privacy Mode + Allowed Team IDs (Cursor),disableBypassPermissionsMode+ managed settings (Claude Code), and RBAC (Codex) at the org level, not the repo level. - 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 MCP server you allow-listed has filesystem access. An over-broad MCP server can read the very files your deny list protects. Use
deniedMcpServers/allowedMcpServersin Claude Code managed settings and review each server’s scope before approving it.
What’s Next
Section titled “What’s Next”- Privacy & Security best practices — the day-to-day habits behind these controls.
- Compliance Automation — automating evidence collection in CI.
- Security Operations — runtime monitoring and incident response.
- Cost Governance — budgets, model tiers, and usage controls across teams.