Part of the AI coding agent security checklist

How to check that AI-written code is secure

An agent can tell you its code is secure. That is an opinion from the same model that wrote it. This guide covers the checks that do not ask the model, where to run them, and what to read in the diff.

$ uvx ranwhat check
Install

Checked against Claude Code's documentation under Sources and ranwhat's source. Published .

01 / Opinion

Why the agent cannot check itself

Ask an agent whether the code it just wrote is secure and it answers from the same context, with the same gaps, that produced the code. If it missed an injection hole while writing, it is likely to miss it while reviewing. The answer is useful as a prompt to look harder. It is not evidence.

Same blind spots The review comes from the model that wrote the change, so a wrong assumption in the first pass tends to survive the second.
A confident tone A model states a guess and a fact in the same voice. Nothing in the answer marks which one you got.
Not repeatable Run the same review twice and the findings can differ. A check you cannot repeat cannot gate anything.
It can be steered Text the agent read while working can change what it reports. See prompt injection in coding agents.
02 / Checks

The checks that do not ask the model

A deterministic check gives the same answer for the same input and does not care who wrote the code. Run several, because each one sees a different kind of problem.

CheckWhat it catchesWhat it misses
TestsBehaviour that no longer works, including a test for the abuse case you thought ofAnything nobody wrote a test for, and tests the agent edited to pass
Type checker and linterWhole classes of bug, such as unchecked values and unsafe calls the linter has a rule forLogic errors and anything outside its rule set
Secret scanner on the diffA key or token written into a file that is about to be committedA secret that only lives in a transcript or in the environment
Dependency auditA newly added package with a known vulnerabilityA package with no advisory yet, or a name that is merely a lookalike
Static analysisKnown insecure patterns such as injection sinks and weak crypto, using tools like Semgrep or CodeQLDesign flaws, missing authorisation checks, business logic

None of these proves the code is secure. Together they remove the mistakes that machines can find, so that your review time goes to the ones they cannot.

03 / Where

Run them where the agent cannot skip them

A check that the agent decides to run is a check it can decide not to run, or edit. Put the gate outside its choices.

CI on the pull request Run tests, the linter, the scanner and the audit as required status checks, with branch protection so that a failing check blocks the merge. The agent can open the pull request. It cannot approve its own.
A pre-commit hook Runs on your machine before a commit is made. Quick and local, and a person can bypass it, so treat it as a courtesy and let CI be the gate.
A Claude Code hook A hook runs a command you wrote at fixed points, such as after an edit, outside the model's decision. It can run the linter after every file change, or refuse a risky call. See Claude Code hooks for security. A hook runs with your full access and the sandbox does not cover it, so keep hook scripts in a place the agent cannot edit.
Protect the checks Treat the test files, the CI workflow, .claude/settings.json and any hook scripts as sensitive. A change to one of them in a diff deserves a closer look than the feature it came with.
04 / Diff

Read the diff, not the summary

The agent's summary says what it meant to do. The diff says what it did. Claude Code's own guidance is to review the changes it proposes before you approve them.

New dependencies A package you did not ask for, or a name one letter off a popular one. Open the manifest and the lockfile changes first.
Network calls A new request to a host you do not recognise, or data sent out that the feature has no need to send.
Credentials A key in a file, a token in a log line, or a value read from the environment and written somewhere else.
Changes to the guardrails Edited tests, loosened lint rules, a skipped check, a new line in a workflow file, or a hook or setting that widens what the agent may do.
Authorisation Whether each new route or function checks who is asking. Scanners find this rarely, and models forget it often, so look for it yourself.
05 / ranwhat

What ranwhat does here, and what it does not

ranwhat does not review code. It reads the history your agents already keep, and it looks at what the agent did and what it left behind.

$ uvx ranwhat check
Install

check and watch flag risky actions in the history, such as a credential read, a local file sent to the network, a publish, or a destructive command. clean finds secrets that ended up in transcripts on disk. None of that says whether the code is correct or secure, so it sits beside your tests and scanners and does not replace them. It also blocks nothing unless you install its Claude Code hook.

06 / Next

Where to go from here

Set up the boundary before the review: the secure-by-default setup lists the settings that limit what an agent can do in the first place. For a gate in the agent's own loop, read Claude Code hooks for security. The full list is on the guides page.