PR Security for Coding Agents: A Verification-First Playbook
When agents write the PRs, classic scanners create alert fatigue at scale. Here's the loop that keeps security signal high without slowing delivery.
The scanner isn't broken. It's just not built for this pace.
Static analysis was calibrated for a world where a developer writes 50 to 200 lines per commit, one feature at a time. That world is over. Claude Code and Cursor can produce a 400-line diff introducing a new auth flow, a payment integration, and a set of admin endpoints in a single task completion. The security surface area of one commit is now what used to be a sprint.
At that scale, pattern-based scanning creates noise faster than teams can process it. A Semgrep rule written to catch manual SQL string concatenation fires on generated code that uses a safe ORM wrapper because the AST pattern looks similar. Developers see 12 alerts per PR. Three are real. They stop reading. The scanner becomes background noise.
Alert fatigue in a human review workflow is bad. Alert fatigue in an agent review workflow is worse. Agents that learn to ignore the scanner either skip fixes entirely or write patches that address the surface pattern without understanding the underlying issue.
The loop that actually works when agents are writing code
Here's what the workflow looks like when it works: agent writes a feature → pre-commit hook runs composed check --json → non-zero exit code with structured findings goes back to the agent context → agent reads the file/line/payload and implements a targeted fix → re-runs scan, gets clean exit → opens PR → Composed Review runs async verification against staging → PR comment: 'Verified Exploitable' or 'No findings confirmed.'
No human required in steps 1 through 6. The human reviewer sees a pre-triaged, pre-verified set of findings, not raw scanner output from a tool that cried wolf on every PR this week.
The key design principle: the security output needs to be machine-readable first, human-readable second. Exit code 0 means clean. Exit code 1 means verified findings. Structured JSON with file, line, CWE, payload, and remediation steps. An agent consumes this the same way it consumes a failing test suite: it reads the output, writes the fix, and re-runs.
Two numbers that tell you if your scanner is helping or hurting
True positive rate (what fraction of flagged findings are real vulnerabilities) and time-to-verify (how long from flag to confirmed exploitable). If your TPR is below 50%, your scanner is making your developers worse at security. It's actively training them that alerts are noise.
For Composed Review, we benchmark at 93% TPR against a synthetic corpus of intentionally vulnerable endpoints across the 7 vulnerability classes we cover. The goal isn't a perfect scanner. It's signal density high enough that when something gets flagged, it gets taken seriously.
Time-to-verify matters because the longer the gap between 'this might be a problem' and 'this is definitely a problem', the more other decisions get made in that gap. Verification in under 90 seconds means it completes before the PR review starts.
What the finding needs to contain for an agent to fix it correctly
A finding your agent can act on looks like this: {"type": "sql_injection", "file": "src/api/auth.ts", "line": 40, "parameter": "user_id", "payload": "' OR '1'='1' --", "evidence": "200 OK, 847 rows returned", "cwe": "CWE-89", "fix": "Use parameterized query"}.
Exit code 1, structured JSON, exact location. The agent reads it the same way it reads a failing test. It knows what failed, it knows where, it writes a targeted fix. No interpretation required. No back-and-forth to establish what kind of injection or what parameter.
This is why the design of security tooling for agent workflows is different from security tooling for human workflows. Humans need context, explanation, and severity scoring. Agents need structured, deterministic, actionable facts.
Run Composed on your last 10 PRs.
Apply for design partner access and we’ll show which findings are real, exploitable, and worth fixing — free.
Run it on 10 PRs →