Short version: sometimes. The question is more interesting than yes-or-no, and anyone telling you "AI code is fine" or "AI code is dangerous" is selling you something. Let me give you the version that's actually useful when you're deciding whether to ship.

What AI assistants actually get right

Before the doom: credit where it's due. Modern coding assistants are good at a real list of things, and pretending otherwise is just as misleading as pretending they're flawless.

They write idiomatic plumbing — connecting two APIs, parsing a CSV, building a paginated listing, drafting a migration. They refactor existing code without changing behaviour surprisingly well. They generate test scaffolding faster than any human. They write doc comments and READMEs that nobody human will ever write themselves. They translate between frameworks if you give them a clear example. They're tireless and they don't get bored.

A surprising amount of "AI code looks right and isn't" turns out to be code that looks right and is right — for the case the developer described. The bugs come at the edges: the case the developer didn't describe.

What they get wrong, consistently

The categories of "right for what you asked, wrong for what's actually out there" are depressingly predictable. After looking at enough AI-generated PHP, you can almost guess which ones a given codebase has before you open the file.

  • Trust boundaries. The assistant doesn't naturally distinguish between "data I just made up in this scope" and "data that arrived from the user 30 lines ago and is now indistinguishable from a constant." It writes "SELECT … WHERE id = " . $id because $id looks like an integer in the local context. It came from $_GET['id'], but that fact has faded from the prompt's foreground.
  • The "happy path bias." If you ask for "a login form," the model gives you a login form that works when the credentials are correct. The failure cases (wrong password five times in a row, locked account, expired session, race between two devices) get handled if you ask. They tend not to come up if you don't.
  • Framework idioms it half-remembers. A model trained on a thousand framework variants is often confidently wrong about exactly which one yours is. Laravel ships CSRF by default; raw PHP doesn't; UserSpice ships the helper but you still have to call it. The assistant will sometimes assume you're on whichever framework was loudest in the training data.
  • Cryptography. AI's prior on "I need a random string" is shockingly weak. md5(uniqid()), str_shuffle, mt_rand() — all of these show up in fresh generations as recently as last week. Real CSPRNG functions (random_bytes) have been in PHP for nearly a decade and somehow still don't win the model's default.
  • Absence of code. Some bugs are things the model didn't write — there's no rate limit on the login endpoint, no audit row when an admin deletes a user, no CSP header on the response. Static analysers can flag the presence of bad code; they struggle to flag the absence of good code.

The full enumeration with code samples is on the 10 most common security holes in vibe-coded PHP page — same categories, ten concrete examples.

Why this happens (it's not laziness)

Three things compound to produce most of the failures above. None of them are the model "being careless." They're structural.

The training distribution is a long tail of mediocre code. Every "PHP tutorial for beginners" blog post from 2007 to about 2020 had concatenated SQL queries. Those blog posts ranked, got copied into Stack Overflow answers, and ended up in the pretraining corpus thousands of times. The model has seen orders of magnitude more concatenated-SQL than it has seen $pdo->prepare(). Its default isn't the better idea; it's the most-frequent idea.

The assistant can't run your tests. A human developer pasting a snippet from Stack Overflow at least runs the page and sees if it crashes. Most AI workflows ship code that hasn't been executed by anyone yet — not even the model. Anything that would only manifest under real load, real user input, or a real attacker's payload doesn't get caught at write-time.

Context windows are short and project-specific knowledge is missing. The model doesn't know that your $db is the UserSpice DB class versus a raw PDO handle. It doesn't know that your project has a RateLimit class that's already configured. It doesn't know that permission_id = 2 is "admin" in your data model. So it makes plausible guesses, and plausible guesses are often the unsafe option.

The maturity spectrum

"AI-generated code" is doing a lot of work as a phrase. There's a spectrum, and where your project sits on it matters more than which model you used.

At one end: a senior engineer who reviews every diff, asks the model targeted questions, runs tests, and treats the assistant like a faster typist. The code that comes out is about as safe as that engineer's hand-written code — sometimes better, because the model catches simple mistakes the human would.

In the middle: someone using the AI to scaffold large chunks, then reading and editing. Mixed results. The reading-and-editing step catches the obvious stuff; the subtle stuff (off-by-one trust boundaries, missing edge cases) tends to ship anyway because the reader starts to trust the model's confidence.

At the far end: a few prompts and a deployed site. This is "vibe coding" as the term is currently used. The code can be impressive — full features in an afternoon — and it can also have every failure mode in the list above simultaneously. Not because the model is bad, but because nobody between the model and the production server has read the diff with the eye of someone looking for trouble.

None of these are wrong ways to work. The fast end exists for good reasons (prototype velocity, low-stakes side projects, learning). The point is: where you are on the spectrum determines what "safe enough" means, and you should know which one you're answering for.

What changes the answer to "yes"

Three things, roughly in order of cost-to-do:

Give the assistant your project's actual conventions. The single biggest lift is the cheapest: a CLAUDE.md file (or equivalent) at the root of the project that tells the model what framework you're on, which helpers handle CSRF / SQL / escaping, and what NOT to do. On UserSpice, the AI Prompts plugin drops a folder of agent-readable docs into usersc/plugins/ai_prompts/ that an AI can read on its own. The same approach works for any framework — write your conventions down where the assistant will read them.

Add an audit step before merge. Either a human eye or an AI agent specifically prompted to look for security issues. On UserSpice this is /userspice-audit — a Claude Code skill that walks every custom file and reports violations against a 12-rule checklist. The equivalent for any project is "ask the assistant to review what it just wrote, with a security checklist in the prompt." Different assistant session, different mindset, finds different things.

Run a real scanner before deploy. Semgrep, Psalm, Trivy, ZAP, Gitleaks — free, fast, container-friendly tools that catch the mechanical version of most of the bugs above. On UserSpice they're bundled with framework-aware rule packs as the Security Scanner. The tools are good enough that "didn't run a scanner before going live" is now a real flag in itself.

A project with all three of these in place is fine. A project with none of them is rolling the dice on the training-distribution lottery.

The bottom line

AI-generated PHP can be safe. The default is to ship code that looks fine and has at least one obvious security bug — that's the training data talking. The fix is structural: give the assistant context, audit before merge, scan before deploy. Done right, you keep the speed advantage; done wrong, you trade "ship in a week" for "rewrite in a quarter."

If you'd rather not figure out the answer in production, the form below goes straight to us — paste a repo URL or a few file paths and we'll tell you specifically what's in your code rather than the average.

Get a real answer about your code

Want a real answer about your specific codebase? Send a repo or a few files and we'll tell you what we find.

We reply within 1–2 business days.