Security Operations with AI
Snyk just flagged 14 “critical” CVEs in your dependency tree. Eleven are in dev-only packages that never ship, two are unreachable from any code path you actually call, and the one that matters is buried at the bottom of the report. Your release is blocked while you triage by hand, again. The promise of “AI security” is rarely a new scanner — it is an assistant that reads the scanner output the way a senior engineer would: separating real exploitable findings from noise, and turning the real ones into reviewed pull requests instead of a 200-line JSON dump nobody opens.
This guide builds that loop with tools that exist today — Semgrep, npm audit, detect-secrets, Trivy, and the GitHub MCP server — driven from Cursor, Claude Code, or Codex.
What you’ll walk away with
Section titled “What you’ll walk away with”- A triage prompt that turns a raw
semgrep --config=autodump into ranked, exploitable-vs-false-positive findings with minimal patches - A dependency-CVE prompt that reads
npm audit --jsonand tells you which CVEs are actually reachable in your code - A secret-rotation prompt for when detect-secrets finds a live credential in history
- The per-tool mechanics for running this loop in Cursor (agent mode + MCP), Claude Code (headless
-pin CI + hooks), and Codex (cloud automation + GitHub) - A CI job that runs the scan-and-triage step on every PR and fails on genuinely new high-severity findings
The workflow: scan, triage, remediate
Section titled “The workflow: scan, triage, remediate”The mistake most teams make is wiring AI to replace the scanner. The scanner (Semgrep, CodeQL, Trivy) is deterministic, fast, and auditable — keep it. The AI’s job is the expensive part a human currently does: reading the findings, ruling out false positives, and proposing the smallest correct fix. The loop is three steps.
-
Run the deterministic scanners and capture machine-readable output. These are real commands, not prompts — paste them into a terminal:
Terminal window # Static analysis (registry rules)semgrep --config=auto --json --output semgrep.json .# Dependency CVEsnpm audit --json > audit.json# Secrets in working tree + historydetect-secrets scan --all-files > secrets.json# Container image (if you ship one)trivy image --format json --output trivy.json myapp:latestsemgrepinstalls viapip install semgreporbrew install semgrep;detect-secretsviapip install detect-secrets;trivyviabrew install trivyor its install script. None of these are npm packages — do notnpm installthem. -
Hand the output to the AI for triage. This is where the value is. The scanner says “potential SQL injection at
db.ts:42”; the assistant tells you whetherdb.ts:42is reachable from untrusted input or is a parameterized query the rule mis-flagged. Use the triage prompt below. -
Turn the real findings into a reviewed PR — never an auto-merged one. Let the AI draft the patch and the PR body, but a human (or a required CI gate) approves it. Auto-applying AI patches to a security-sensitive file is how you ship a regression with a green checkmark.
The mechanics of steps 2 and 3 differ per tool. The scanner commands in step 1 are identical everywhere.
Open the repo in Cursor, run the scanners so semgrep.json / audit.json exist in the workspace, then drop into Agent mode (Cmd/Ctrl+I). Agent mode can read the JSON files directly and edit the flagged source files in place, showing each change as a checkpoint you accept or reject.
Add the GitHub MCP server so the agent can open the remediation PR without leaving the editor. In Cursor’s MCP settings (or .cursor/mcp.json), register the official remote server:
{ "mcpServers": { "github": { "url": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer ${GITHUB_PAT}" } } }}Now the agent reads semgrep.json, patches the two real findings, and calls the GitHub MCP create_pull_request tool — all from one prompt.
Claude Code shines for the headless, in-CI half of this loop. Run the scanners, then pipe the triage prompt through -p (print mode) with the JSON on disk:
semgrep --config=auto --json --output semgrep.json .claude -p "Read semgrep.json. For each finding, classify exploitable vs \ false-positive and output JSON: {file, line, verdict, reason, patch}. \ Treat anything under test/ or scripts/ as non-shipping." \ --allowedTools "Read,Grep" --output-format json > triage.jsonAdd the GitHub MCP server with the documented HTTP transport so Claude Code can open the PR locally or in CI:
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \ --header "Authorization: Bearer ${GITHUB_PAT}"A PreToolUse hook is the right place to enforce the “no auto-merge of security fixes” rule — block any Bash(gh pr merge*) on a branch named security-* and require human review.
Codex (GPT-5.5 across App/CLI/IDE/Cloud) is strongest for the scheduled, hands-off variant. Run the triage from the CLI against captured output:
semgrep --config=auto --json --output semgrep.json .codex exec "Read semgrep.json and rank findings by real exploitability; \ propose a minimal patch for each genuinely exploitable one." \ --ask-for-approval on-requestFor the recurring scan, use Codex Cloud with its GitHub integration: point a Cloud task at the repo on a schedule, let it run the scanners and triage, and have it open the remediation PR through the connected GitHub app. Keep --ask-for-approval on-request (not never) so a destructive remediation still pauses for a human.
Copy-paste prompts
Section titled “Copy-paste prompts”These are the recipes. They assume you have already captured the scanner JSON as described above.
MCP servers and skills for this loop
Section titled “MCP servers and skills for this loop”Two extensibility options change this workflow, and they are not interchangeable.
- GitHub MCP server (
github/github-mcp-server, remote athttps://api.githubcopilot.com/mcp/) is the persistent connection: it lets the agent search code across the org, read Dependabot/secret-scanning alerts, and open the remediation PR. Use it when the agent needs to act on GitHub repeatedly. There is no@anthropic/*or one-stringnew MCPClient('github')convenience layer — MCP isconnect(transport)thencallTool({ name, arguments }). If you script directly against the SDK, the package is@modelcontextprotocol/sdkand the client lives at@modelcontextprotocol/sdk/client/index.js. - The Semgrep skill (
semgrep/skills, installable withnpx skills add semgrep/skills) is the lighter-weight option: it teaches the agent to write custom Semgrep rules for your codebase and run scans, without standing up a server. Reach for the skill when the job is “author and run rules”; reach for the MCP server when the job is “operate on GitHub.”
Hardening the cluster (current Kubernetes)
Section titled “Hardening the cluster (current Kubernetes)”If you ship to Kubernetes, the AI can draft your admission policy — but it must draft the current one. PodSecurityPolicy (policy/v1beta1) was removed in Kubernetes 1.25 and does not exist on any supported cluster. The supported successor is Pod Security Admission via namespace labels, paired with a NetworkPolicy for traffic isolation.
# namespace with Pod Security Standards enforced (replaces PodSecurityPolicy)apiVersion: v1kind: Namespacemetadata: name: payments labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest pod-security.kubernetes.io/warn: restricted---# default-deny egress/ingress, then allow only what's neededapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: payments-isolation namespace: paymentsspec: podSelector: matchLabels: app: payments-api policyTypes: [Ingress, Egress] ingress: - from: - podSelector: matchLabels: { app: api-gateway } ports: - { protocol: TCP, port: 8443 } egress: - to: - podSelector: matchLabels: { app: postgres } ports: - { protocol: TCP, port: 5432 }Wiring it into CI
Section titled “Wiring it into CI”Run the deterministic scanners on every PR, then run the AI triage as an advisory step. The hard gate stays deterministic — the pipeline fails on genuinely new high-severity findings from Semgrep/Trivy, not on the AI’s opinion. Note actions/checkout@v5 (Node 24; v3 runners are end-of-life as of June 2026).
name: Security Scanon: pull_request: schedule: - cron: '0 */6 * * *'
jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5
- name: Semgrep (hard gate on new high-severity) uses: semgrep/semgrep-action@v1 with: config: auto
- name: Dependency audit run: npm audit --audit-level=high
- name: Secret scan run: | pipx install detect-secrets detect-secrets scan --all-files | tee secrets.json
# Advisory: AI triage summary posted to the PR, not a blocker - name: AI triage (advisory) if: github.event_name == 'pull_request' run: | semgrep --config=auto --json --output semgrep.json . || true claude -p "Summarize semgrep.json: rank exploitable findings, list \ likely false positives, suggest the smallest fix for each real one." \ --allowedTools "Read,Grep" --output-format json > triage.json env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}