Founder pricing: Pro at $9.99/mo forever for the first 50 members. 18 of 50 left Claim yours →
All posts

How to keep AI-generated code from shipping security holes

The SanuDesk team 5 min read
security vulnerabilities ai agents

The endpoint works. You tested it. The tests pass.

It also returns any customer's invoice to anyone who edits the ID in the URL, because the controller checks that you're logged in and never checks that the record is yours.

Nothing about that failure is loud. No red test, no exception, no warning. The feature does exactly what you asked for, and the missing part was never in the brief.

Why agents skip the security parts

Not malice, and not a weak model. Three structural reasons, true of every coding agent.

Working code is the objective. An agent optimises for what it can observe: the code runs, the test goes green. A missing permission check produces no signal at all: absence is invisible to a loop built on failures.

Its training is mostly demo code. Tutorials and answers online strip out the auth middleware and the validation because they obscure the point being taught. That's the median example of "how to do X".

It can't see your threat model. It doesn't know this route is public, that this parameter is user-supplied, or that this table holds other people's data. You know. It's just never in the context window.

The five misses that actually recur

  • Authorization, not authentication. By far the most common: the code confirms someone is logged in, then loads a record by ID with no ownership check.
  • Input trusted at the boundary. String-built SQL when the ORM's binding was right there. User data interpolated into a shell command or a file path.
  • Secrets that drift into the repo. A key hardcoded "just to get it working", a real token pasted into a test fixture, .env values in a debug log.
  • Dependencies you didn't ask for. A package pulled in for a ten-line problem, and occasionally one that doesn't exist under that exact name, which is the gap typosquatters sit in. Check the name and the last release before it lands.
  • Errors that overshare. Debug mode left on, stack traces returned to the client, exception text that names your table and column.

None of these look like bad code in review. They look like normal code with something quietly absent.

Say what the threat model is

Agents follow explicit constraints well, and invent their own when you give none, always the friendly case. So put the hostile framing in the prompt:

  • "This route is public. Treat every parameter as attacker-controlled."
  • "Scope every query to the current user. Never load by ID alone."
  • "No string-built SQL. Use the query builder's bindings."

Better still, point at code that already does it right: "match the authorization pattern in OrderController." An example in the repo beats a paragraph of principle.

Anything you'd repeat every session belongs in your AGENTS.md instead: four lines there apply to every agent, in every session.

Give the missing check a way to go red

The deepest fix turns invisible absences into visible failures: tests that assert the negative.

  • User B requesting user A's record gets a 404.
  • An unauthenticated request to the admin route gets a 401.

Write those first and the agent has something to satisfy. The TDD loop works here for the same reason it works elsewhere: it turns intent into a check the agent can run without you.

Back that with cheap automation: dependency audits, secret scanning in a pre-commit hook, whatever static analysis your stack has. Be honest about the limits, though. Those tools find injection shapes and committed keys; no linter knows which records belong to which user. Authorization stays yours.

Make a second agent look for it

The session that wrote the code is its worst reviewer: anchored on its own reasoning, happy to explain why each line is fine. A fresh session with a different brief is a genuinely different reader. Give it one job:

Assume every input in this diff is attacker-controlled. What's exploitable, and what would the request look like?

That finds real problems, missing checks, unescaped output, an over-broad CORS header, because it's pattern recognition, which models are good at. Treat it as a smoke alarm, not an audit: it won't know your "archived" flag is load-bearing for billing, and it sounds confident either way. It earns its keep on the boring 80%, so your attention goes to the business logic. Fold it into your usual review of AI-generated code and triage by risk: new routes, changed auth, new dependencies, touched config.

A related failure lives one level up: not what the agent wrote, but what it was persuaded to do by an issue, a doc page or a tool response it read along the way. That's prompt injection, and it needs different containment than a code review pass.

Where this fits in a real workflow

That's the shape SanuDesk is built around. It's a desktop app where your Claude Code, Codex and Gemini sessions tile into one grid, so the security pass is a second session running beside the one still building, not a task you skip after lunch.

Beside every session sits a git pane with live diffs, so a new dependency or a modified .env shows up while it happens, not three commits later. Work arrives from a Kanban board, and a card carries its constraints into the session it's deployed to (for example "public route, scope to the current user" written once, briefed every time), then returns to review with a what-changed note.

Loops cover what you'd otherwise forget: a weekly sweep for hardcoded secrets and unchecked routes, journaled so the next run starts sharper. It drives the agent subscription you already pay for, and the free tier doesn't need one of ours.

Ship fast, verify cheaply

You don't need a security programme. Say what's hostile in the brief, write the tests that fail when a check goes missing, and let a fresh agent try to break the diff before you merge.

Ten minutes a feature, the difference between shipping quickly and shipping quickly into an incident.

Download SanuDesk free and point a workspace at your repo, or see how the grid, the git pane and the board fit together on the features page.

Run your own fleet of agents

SanuDesk is a free desktop app that tiles your Claude Code and Codex sessions and gives every project a Kanban board your agents work from.