The tools are excellent and you should keep using them. But it is worth understanding what they optimise for, because working code and secure code overlap heavily without being the same set, and the gap between them has a specific and repeatable shape.
Why are the vulnerabilities so consistent?
A language model reproduces the distribution it was trained on. That distribution is dominated by tutorial code, library examples written for readability, and Stack Overflow answers written for brevity. In all three genres, the security-relevant lines are the first thing removed. A tutorial that parameterises every query, validates every session, and handles every timeout is a bad tutorial, because the teaching point drowns.
So the model learned an idiom of code where hardening is absent, and it reproduces that idiom faithfully. The result is predictable, and predictable is good: you can check for four specific things instead of auditing everything.
1. SQL injection via template literals
The most common finding in AI-generated database code, and the one most likely to pass a human review, because the modern syntax reads as current and clean rather than as the classic string-concatenation smell people were trained to spot.
const query = `SELECT * FROM users WHERE username = '${username}'`
const result = await db.query(query)
// Supplied as username: ' OR '1'='1' --
// Resulting query returns every row in the table.The models know parameterisation. They produce it when asked explicitly. They do not reliably default to it, and defaults are what ship.
const result = await db.query(
'SELECT * FROM users WHERE username = $1',
[username],
)2. Insecure direct object references (IDOR)
The highest-frequency critical finding. The route authenticates correctly and then fetches by an identifier taken straight from the request, so any logged-in account can read any record by changing a number.
router.get('/api/invoices/:id', authenticate, async (req, res) => {
const invoice = await Invoice.findById(req.params.id)
return res.json(invoice) // any user, any invoice
})The fix is to scope the query by the session's user rather than guarding it afterwards, as covered in the pre-deployment checklist. What makes IDOR particularly costly is that exploiting it requires no tooling and leaves ordinary-looking traffic in your logs. It is indistinguishable from normal use until someone notices the volume.
3. Hardcoded credentials
When a context window contains configuration examples, models reproduce the shape, including plausible-looking literal secrets. These get committed, pushed, and picked up by automated scanners within minutes of touching a public repository. Credential-stuffing infrastructure monitors new public commits continuously; the window between push and exploitation is measured in minutes, not days.
const db = new Database({
host: 'prod-db.internal',
password: 'sup3rS3cur3P@ss', // literal secret in source control
})Every credential belongs in an environment variable, without exception. If one has already been committed, rotate it first and clean the history second. The ordering matters, because the commit is already public and rotation is what actually closes the exposure.
4. Permissive CORS
This one almost always enters the codebase as a local development fix. A CORS error blocks progress, the model resolves it with a wildcard, the error disappears, and nobody returns to it because nothing is visibly broken.
app.use(cors({ origin: '*' }))
// Intended
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') ?? [],
credentials: true,
}))Why manual review misses all four
Because the file around the defect is genuinely well written. Clean route organisation, consistent error shapes, sensible names, complete comments. Human review is a pattern-matching process, and every pattern says this file is fine, so attention drops precisely where it needs to rise.
That is the structural argument for automated specialist review on AI-generated code specifically: it applies the same scrutiny to every line regardless of how good the neighbourhood looks. If you are choosing a tool for this, the comparison of AI code review tools covers what each category can and cannot detect.