Anthropic Shipped an AI Security Scanner. Here's the Per-PR Cost Math.
Before you add anything to CI, know exactly what it costs per pull request and how to triage what it finds.
The first time my manager asked, “Are we using AI to scan PRs for vulnerabilities yet?" I said I'd look into it. Then I spent four hours reading docs, pricing pages, and GitHub issues before I had a number I trusted enough to put in a Slack message.
That should have taken twenty minutes. The number exists. The math is straightforward. Nobody had written it down in one place where a platform engineer could find it.
Anthropic quietly shipped `anthropics/claude-code-security-review` as a first-party GitHub Action. You add a workflow file, point it at a secret, and it posts a findings comment on every pull request. The scanner reasons about code rather than matching signatures, which means it catches things like logic-level injection paths that a regex-based tool would miss. It also means the false-positive profile is different from what you're used to, and you need a triage process before you wire it to branch protection.
This article gives you the cost math and the triage playbook in full. Both are things you'd need even if you built this yourself.
Why "Just Run It" Isn't a Strategy
Adding a CI step that calls an LLM API isn't free, and it isn't free to manage. There are two failure modes I see teams hit.
The first is budget surprise. Someone adds the scanner, it runs for a month, the cloud bill shows up, and the conversation gets uncomfortable because nobody did the math upfront. The scanner doesn't cost a lot, but "not a lot" needs a number attached to it before you walk into a budget conversation.
The second failure mode is alert fatigue. The scanner finds something on every PR. Engineers start skimming the findings comment the same way they skim Dependabot. One day there's a real SQL injection in a PR, it's buried in a list of five findings, and it merges. The triage process is what keeps findings meaningful instead of noise.
Both problems are solvable. The math takes ten minutes. The triage rubric takes one meeting to agree on. Neither requires buying anything yet.
What This Costs Per PR (The Real Numbers)
Claude bills per token. One token is roughly four characters of text. A PR diff gets converted to tokens and sent to the model as input. The model's findings comment is output tokens. The formula is simple:
Cost = (input_tokens × input_rate) + (output_tokens × output_rate)For Claude Sonnet 4.6, the rates are approximately $3 per million input tokens and $15 per million output tokens. (Verify current pricing at platform.anthropic.com before your next budget conversation. Rates change.)
Scenario 1: A 200-Line PR Diff
A focused bug fix or small feature. Maybe three files changed.
Component Tokens Rate Cost
-----------------------------------------------------------------------
System prompt + workflow context (input) 2,000 $3.00 / 1M $0.006
PR diff, ~200 lines (input) 1,300 $3.00 / 1M $0.004
Findings output, 1-2 findings (output) 600 $15.00 / 1M $0.009
-----------------------------------------------------------------------
Total per PR ~$0.019Call it two cents. For a small PR, this is a rounding error.
Scenario 2: A 2,000-Line PR Diff
A refactor, a new feature, a dependency upgrade touching multiple services.
Component Tokens Rate Cost
------------------------------------------------------------------------
System prompt + workflow context (input) 2,000 $3.00 / 1M $0.006
PR diff, ~2,000 lines (input) 13,000 $3.00 / 1M $0.039
Findings output, 2-4 findings (output) 1,500 $15.00 / 1M $0.023
------------------------------------------------------------------------
Total per PR ~$0.068Seven cents. Still noise for a single PR.
Monthly Back-of-the-Envelope
The question your manager will ask isn't “What does one PR cost?" It's “What does this cost per month?"
If your team merges 80 PRs a month (about 4 per business day), with a mix of small and medium diffs averaging around $0.04 per scan:
80 PRs × $0.04 = $3.20/monthEven if your average PR runs larger, say closer to the 2,000-line scenario at $0.07 each:
80 PRs × $0.07 = $5.60/monthA busy multi-team repo at 400 PRs a month at $0.07 each is $28/month. That's less than one developer's Spotify subscription. The cost math isn't the obstacle here. The obstacle is having a triage process in place before you flip it on.
One practical note: output token count varies with how many findings the scanner generates. Zero findings produces shorter output and costs less. Ten findings costs a bit more. The estimates above assume one to three findings per PR, which is realistic for an established codebase with existing security hygiene.
The 3-Tier Triage Rubric
Every finding the scanner posts needs to land in one of three buckets. Here's the decision framework.
REAL: Block the merge. Fix it.
A finding is REAL when it describes an exploitable path with proof. The scanner should show you the specific line, and explain how an attacker would reach it, and the explanation should hold up when you read the code yourself. SQL injection via string concatenation in a request handler is REAL. Hardcoded credentials that actually ship to production are REAL.
The discriminator: "If an attacker had this codebase and five minutes, could they demonstrate this?" If yes, it's REAL. Block the PR and fix it before merge.
PROBABLE: Human review required.
A finding is PROBABLE when the pattern is plausible, but context matters. The scanner can see the diff, not the full runtime environment. A finding might flag a code path that looks injectable, but your framework wraps every database call with prepared statements at a layer the scanner can't see. Or the flagged code only runs in a context that requires prior authentication the scanner doesn't know about.
The discriminator: "This could be real, but I need someone who knows this codebase to confirm." Don't block the PR automatically. Route it to the PR author or a senior engineer. Give it a two-hour resolution window before it escalates.
DISCARD: Suppress it with a documented rule.
A finding is DISCARD when it's structurally a false positive. The scanner flagged test code that never runs in production. It flagged a generated file you don't own. It flagged a template placeholder in an IaC file that gets substituted at deploy time. It flagged a public API URL as a hardcoded credential because the word "key" appeared in the variable name.
The discriminator: "Would an attacker gain anything by knowing this?" If no, it's a DISCARD. The important part is that you document why. Suppressing without a comment is how you end up silently ignoring real findings six months later when the context is gone.
A Worked Example: The SQLAlchemy False Positive
Here's the kind of finding that will show up on your team in the first two weeks if you use any ORM.
A PR adds a new search endpoint. Somewhere in the diff, there's code like this:
def search_users(search_term: str):
results = db.session.query(User).filter(
User.name.ilike(f"%{search_term}%")
).all()
return resultsThe scanner flags it as a potential SQL injection vulnerability. The finding explains that `search_term` appears to be user-controlled input and is being interpolated into a query string. Severity: HIGH.
A human reading this would notice a few things. The code uses SQLAlchemy's ORM layer. The `.ilike()` method is a SQLAlchemy query construct, not a raw SQL string. SQLAlchemy sends the query to the database as a parameterized statement with the value bound separately, which is exactly the defense against SQL injection. The `f"%{search_term}%"` is constructing the pattern string in Python, but that pattern gets passed as a bound parameter by the driver.
This is a DISCARD. The scanner saw string interpolation near a database call and correctly identified that as a pattern worth flagging. It couldn't see that the ORM handles parameterization automatically.
The suppression note you'd document reads something like:
SQLAlchemy ORM calls via `.filter()`, `.ilike()`, `.like()`, and similar query methods use parameterized queries automatically. String interpolation to construct pattern values (e.g., for LIKE clauses) does not create injection risk when using these methods. Do not flag SQLAlchemy ORM filter calls as SQL injection.
That note goes into a filter file your workflow references. The same class of finding stops appearing on every PR that touches a database query.
Two things to notice about this example. First, the scanner wasn't wrong to flag it. Without ORM context, string interpolation near a SQL-like method call is exactly what a good scanner should notice. Second, the suppression is better than just dismissing it, because the documented rule now covers every future PR using the same pattern. You pay the triage cost once.
What the Full Kit Covers
The cost math and triage rubric are the foundation, but they don't tell you how to wire any of this into GitHub.
The full guide covers the GitHub Actions workflow YAML itself (the one that calls `anthropics/claude-code-security-review` and handles the findings response), how to set up branch protection so that HIGH findings actually block merges instead of just posting a comment, and the in-workflow automation that runs the REAL/PROBABLE/DISCARD classification before the comment lands on the PR.
There's also a head-to-head with GPT-4o as a second-opinion scanner. They're not equivalent tools. The Anthropic action is purpose-built for this job. The GPT-4o path is a chat completions API call with a security prompt, which costs about seven times less per PR but produces more variable results. The comparison matrix helps you decide whether a two-week pilot with both scanners running simultaneously is worth the extra spend.
The suppression filter file format is documented in full, with a worked example filter file for a Next.js and SQLAlchemy codebase that covers the five most common false-positive patterns before you even see your first finding.
One Thing Before You Add It to CI
The scanner is easy to add. Ten minutes from zero to your first findings comment. The harder question is whether your team has agreed on what to do with those findings before the first PR triggers.
That conversation takes one team meeting. You need three agreements: what severity blocks a merge automatically, who owns the weekly rotation for PROBABLE findings that authors didn't resolve, and what the bar is for adding a DISCARD rule.
If you want to run that meeting with the cost math and triage rubric in hand, you have both now. If you want the workflow YAML, the branch protection setup, and the suppression filter format so you're not building those from scratch, the full guide is at the link below.
What's your current setup for catching security issues in PRs before they merge? Genuinely curious whether teams are using static analysis tools, relying on code review, or still treating it as a post-deploy problem.
The full CI/CD template with GitHub Actions workflow, merge-gating logic, and false-positive triage automation is at the ASTGL store.




