Contents
In brief
Code from GitHub Copilot and Claude Code often looks ready to run — which is exactly why the same classes of holes keep shipping. On Dev.to, engineer Jitendra Rout argues these are not random model blunders. Assistants optimize for a plausible runnable sample, not a production-hardened patch. He published an open catalog and a scanner, ai-vuln-scan, so teams can catch the gap systematically instead of hoping a better prompt will save them.
What happened
Generic linters hunt bugs in general. Rout asked a narrower question: which mistakes show up more often in AI-assisted code than in code a human wrote from scratch? A demo does not need a secrets manager, parameterized queries, or a locked-down config. The model emits the version that works. The safe version appears only when the prompt demands it.
The public AI Vulnerability Pattern Catalog lists seven shapes:
| Pattern | What the “helpful sample” does | What production needs |
|---|---|---|
| Hardcoded secrets | A fake-looking API key gets pasted for real | Env vars / a secret store |
| String-built queries | SELECT ... WHERE id = ${userId} |
Driver parameters |
| Shell interpolation | exec("cmd " + arg) |
execFile() with an argv array |
| Permissive config | Wildcard CORS, TLS verify off | Explicit origins, verification on |
| Weak crypto | MD5 / Math.random() for tokens |
Real security primitives |
| Auth drift across similar routes | A new route “like the others” without middleware | The same auth layer as siblings |
| Verbose errors | err.stack in the HTTP body |
Server logs, generic client message |
Pattern six is the most AI-flavored. A human copy-pasting a route tends to keep the whole block. A model regenerates from a description, and the auth step can drop — especially across separate prompts. Each handler still reads fine in isolation. The article’s Express sketch is a user-orders route that only reads id from the path and returns JSON. If sibling routes in the same file wrap in auth middleware and this one does not, the hole does not scream via syntax. It looks like “just another simple endpoint.”
On a sample file seeded with these issues, ai-vuln-scan reported 12 findings (secrets, query construction, a missing-auth route, weak token RNG) and zero false positives on the same routes rewritten safely. Coverage today is JavaScript, TypeScript, and Python via regex and light structure; the next milestone is AST taint tracking plus a labeled dataset. Rout publishes the catalog separately from the scanner: you can name and debate a new pattern before a detection rule exists. That matters because the assistant zoo changes faster than any regex pack.
Why it matters
Teams already live in assistants. Review still asks “does this function look reasonable?” more often than “did auth fall off during regeneration?” ESLint security plugins, Bandit, and Semgrep catch some of this — generically, without the “this is a typical AI artifact” frame. A named catalog gives review and CI a shared vocabulary: you argue with a pattern, not a vibe that “the model is hostile.”
There is an org effect too. If the team already bans committed keys and string-built SQL, the catalog is still a list of places where an assistant most often sidesteps those rules “to make a working sample.” A plausible-looking key, CORS * “so localhost works,” MD5 “just hash it” — not new security theory, just the statistics of what a model treats as a good enough answer to a short prompt.
A dedicated scanner does not replace an authorization architecture. It covers the blind spot: a plausible sample that compiled and survived a glance.
In practice
- When a new route arrives from an assistant, diff its auth middleware against siblings — that is where drift hides.
- Ban keys and connection strings in source, including “temporary” and “demo” values.
- Flag SQL and shell built from template strings; require parameters and argv arrays.
- Do not leave
CORS *, disabled TLS verification, or debug mode in the committed config — the model does not know your real origins or certs. - Reject
MD5andMath.random()for password hashes and session tokens even in a “draft” PR. - Keep stacks in server logs; return a neutral message and a code to the client.
- Clone
ai-vuln-scan, runnpm run scan:examples, and decide whether it sits beside Semgrep, not instead of it.
Takeaway
AI-generated holes are predictable: the model writes a sample that runs, not a build you can ship. Seven named patterns and a narrow scanner do not retire review — they give names and an automated net where humans miss a dropped auth layer. “Make it secure” in the prompt helps once; a catalog check helps every time.


