PLAINFINCH learn by building

Checking AI-written code

You will review a menu search an AI assistant wrote for the bakery, find its two holes, and fix both.

Why does AI-written code need a security review?

AI assistants are good at producing code that runs. Ask for a menu search and you get one in seconds, and the first time you type rye you see the rye loaf. That success is the trap. Security holes do not show up when honest visitors use a page. They show up when someone types something the code did not expect.

Assistants learn from huge amounts of public code, and much public code is written for demos and tutorials where safety was not the point. The shortest way to build a query or a page is usually the unsafe way, and short answers are what assistants tend to give. They also have no idea which of your values come from visitors unless you tell them.

None of this means you should stop using them. It means AI code gets the same review you would give code from a new colleague: read every line that touches visitor input, a database, a password, a cookie, a header or a package name.

What was wrong with the bakery's search?

Two lines, one mistake. On line 8 the assistant built the SQL with a template string, so the visitor's search text became part of the query. A quote in the search ends the string early and the rest of the text is read as SQL. The Attacker view showed the quote trick returning every row.

On line 10 it put the search text into the page heading with ${req.query.q}. The menu names on line 9 were escaped, because the assistant recognised them as data, but the search term came from the address bar and went into the page unchanged. Anyone could send a link to /search?q= followed by a tag, and the page would run it for whoever clicked.

The fixes are the ones from earlier lessons. Pass the text as a value with a ? placeholder, so the database keeps it apart from the SQL. Wrap it in escapeHtml when it goes into HTML. Neither change affects honest visitors.

const rows = db.all(
  'SELECT name, price FROM menu WHERE name LIKE ?',
  ['%' + req.query.q + '%']
);
res.send(`<h1>Results for ${escapeHtml(req.query.q)}</h1><ul>${list}</ul>`);

How do you review code you did not write?

Start by finding where outside data enters. In Express that means req.body, req.query, req.params, req.headers and req.cookies. Highlight each one. Then follow each value to where it ends up and ask what that destination needs.

A value going into HTML needs escaping. A value going into SQL needs a placeholder. A value used as a price or an amount needs replacing with the server's own figure. A value used as a file name needs checking against a fixed list. A password needs a slow hash. If you cannot say what protects a value at its destination, that is the line to fix.

Then read the settings around the code: headers, cookie flags, CORS lines, and every package name. These are short and easy to skim past, and assistants often get them subtly wrong.

  • Where does visitor text go into HTML, and is it escaped there?
  • Where does it go into SQL, and is it a placeholder value?
  • Does any price, total or role come from the browser?
  • How are passwords hashed, and with what cost?
  • Are any keys typed into the code?
  • Does every package name exist, and is the version current?
  • Do the headers use values current browsers accept?
FigureA review table. Each value from outside is followed to where it ends up and what must protect it there: req.query.q into HTML needs escapeHtml, into SQL needs a placeholder, a price needs the server's own figure, a password needs bcrypt, a package name needs checking on npmjs.com.A review table. Each value from outside is followed to where it ends up and what must protect it there: req.query.q into HTML needs escapeHtml, into SQL needs a placeholder, a price needs the server's own figure, a password needs bcrypt, a package name needs checking on npmjs.com.
Review AI code by following each outside value to where it lands. Every destination needs its own protection; the bakery search was missing two of them.

What mistakes do AI assistants make most often?

Some come up again and again. Visitor text dropped into template strings and innerHTML. SQL built with ${}. Passwords hashed with SHA-256 or MD5, with a comment saying the password is now secure. Access-Control-Allow-Origin: *, or the request's own Origin copied back with credentials, offered as the fix for a CORS error. SameSite=None added because a cookie was not arriving. 'unsafe-inline' added to a Content Security Policy to make errors go away.

Others are out of date. X-Frame-Options: ALLOW-FROM, which browsers dropped years ago. The X-XSS-Protection header, which modern browsers ignore. The csurf package, retired in 2022. Password rules that force symbols and monthly changes, which current guidance from NIST advises against in favour of length and checking against leaked lists.

And some are invented. Package names that sound right and do not exist, function options a library never had, and advice to sanitise input with no detail about which characters, where, or with what. Vague advice is a sign to ask for specifics or check it yourself.

How should you ask an assistant for safer code?

Say what you need in security terms. Instead of asking for a search box, ask for a search route that uses parameterised queries and escapes all output with escape-html. Instead of asking for a sign-up form, ask for one that hashes passwords with bcrypt at cost 12. Assistants follow explicit requirements far better than they guess them.

After you get code back, ask the assistant to review its own answer: which values come from the visitor, and how is each one made safe? This often surfaces problems it skipped the first time. Treat the review as a second opinion. You still read the code yourself, and you still test it, here in the lab or with a real scanner.

What was wrong with the bird club's join page?

The broken version of this lesson has three problems that all came from the same assistant. Each one looks reasonable on a quick read, and that is how they get through.

It hashed passwords with crypto.createHash('sha256'). That is a real hash function, so the line looks responsible. SHA-256 is built to be fast, so someone with a stolen table and one graphics card can test billions of guesses a second, roughly. It suggested a package called bcrypt-fast-hash, which does not exist. It set X-Frame-Options: ALLOW-FROM, which current browsers ignore entirely, so the page can be framed by anyone.

Can automated tools do the review for you?

They help. Linters with security rules such as eslint-plugin-security, code scanners like GitHub code scanning with CodeQL or Semgrep, npm audit, and secret scanners all catch common patterns. Turn on the ones your code host offers for free.

They miss things that need context. A scanner cannot tell that req.body.price should have come from the menu table, or that a route lets one member edit another member's sightings. Those need a person who knows what the site is meant to do.

Where does the lab simplify?

The lab's checks are pattern rules, and AI code is often unusual in shape. A query built in a helper function three files away, or HTML built with a library the lab does not know, can fool it in either direction. A green Report on AI code means the common patterns are fixed. It does not replace reading the code, and a real attacker would try many more inputs than the lab's single payload for each attack.

Field notes

  • AI assistants write code that works and is often unsafe.
  • Review every place visitor input enters: req.query, req.body, req.params, cookies and headers.
  • Watch for string-built SQL, unescaped HTML, trusted prices and outdated headers.
  • Ask for placeholders and escaping by name, then check the result yourself.

Easy to get wrong

Security holes only show up with unexpected input. Code that works for honest visitors can still be wide open.

With a placeholder the database never reads the visitor's text as SQL.

Vague requests get vague answers. Named defences are easy to check in the code that comes back.

Questions people ask

Are some AI tools safer than others?

Newer models make fewer of these mistakes, especially when asked. All of them still make some. Review the code regardless of which tool wrote it.

Should I tell the assistant about my site's security setup?

Yes. Saying that you use escape-html, parameterised queries and bcrypt in a project helps it match. Many tools let you keep these notes in a project file they read every time. Leave real keys out of anything you share.

Is it safe to paste my code into an AI chat?

Remove keys and personal data first. Check your tool's settings for whether chats are used for training, and follow your employer's rules if it is work code.

Keep going