Securing AI-Written Code
In the Security Lab, doors are labelled "secure" whether they lock or not. Sec, the lab's guard, checks every one by hand. AI assistants learned from a huge amount of public code, and a lot of public code is insecure: tutorials that skip validation, quick demos with hardcoded keys, examples that trust whatever the browser sends. So assistants reproduce those patterns, often in code that otherwise looks careful. None of these bugs cause an error when you run the app. They wait for someone to find them.
String-built SQL
The classic one. Code that glues user input into a query lets that input change the query itself:
// Vulnerable: email is pasted straight into the SQL
const result = await db.query(
`SELECT * FROM users WHERE email = '${email}'`
);
// Fixed: a parameterised query keeps data and SQL apart
const result = await db.query(
'SELECT * FROM users WHERE email = $1',
[email]
);
With the first version, an "email" like ' OR '1'='1 returns every user. Parameters ($1, ?, or your library's equivalent) send the value separately, so the database never treats it as SQL. Any template string or + inside a query is worth a second look.
Secrets in the code or in the browser
Assistants often write const API_KEY = "sk-live-..." right into the file, because that's how the example looked. Once committed, it lives in your Git history even after you delete the line. Keep secrets in environment variables on the server, and keep .env files out of Git.
The other version of this mistake is calling a paid or private API directly from frontend code. Anything shipped to the browser, including environment variables bundled into it, can be read by any visitor with developer tools. Secret keys belong on the server, which makes the call on the user's behalf.
Missing auth checks and trusting the client
Two different checks are easy to miss. Authentication: is anyone logged in? Authorization: is this user allowed to do this, to this record? Generated routes often check the first and skip the second:
app.delete('/api/notes/:id', requireLogin, async (req, res) => {
// Only deletes the note if it belongs to the logged-in user
await db.query('DELETE FROM notes WHERE id = $1 AND owner_id = $2',
[req.params.id, req.user.id]);
res.sendStatus(204);
});
Without AND owner_id = $2, any logged-in user could delete anyone's note by changing the id in the URL.
Related: never trust values the client sends when the server can know them. If the checkout request includes price: 1, a user can edit that before it is sent. Look up the price on the server. Hiding a button in the UI is not a security check either, because anyone can call the API directly.
Overly broad CORS
When a browser request fails with a CORS error, assistants often "fix" it by allowing everything, for example cors({ origin: true, credentials: true }), which accepts requests from any website with the user's cookies attached. That lets any site the user visits act as them on your API. Allow only the origins you actually use, such as your own frontend's URL.
What never goes into a prompt
Whatever you paste into an AI tool leaves your machine and may be stored or logged by the provider. Never paste API keys, passwords, database connection strings, the contents of .env, or real users' personal data such as emails, addresses or messages. When you need help with a bug in a query, replace real values with made-up ones. If you ever do paste a real secret by accident, treat it as leaked and rotate it: create a new key and revoke the old one.
A short checklist before merging
Before any AI-written code that touches users, data or money gets merged, go through it with Sec's list:
- Every query uses parameters, never string-built SQL.
- No secrets in the code, the Git history or anything sent to the browser.
- Every route checks who the user is and whether they may act on this record.
- Prices, roles and user ids come from the server, not from the request body.
- CORS allows only your real origins.
- Errors shown to users don't include stack traces or database details.
Five minutes with this list catches most of what assistants get wrong.
Resources
Curated resources for this node are on the way. Use what you already know how to search for, and check back soon.