All posts

January 3, 2026 · 4 min read

I Asked an AI to Add Login. The Admin Page Never Got the Memo.

Sometime last spring I was building a small internal tool for tracking hours across a couple of client projects. Nothing fancy: a dashboard, a database, a page for me to see totals. I had the whole thing running in an afternoon with an AI coding assistant, which is still the part that gets me when I think back on it.

The tool needed a login eventually, since I planned to let a couple of contractors check their own hours without emailing me for it. So I typed something close to add login so only I can see the admin page and let the assistant handle it. It built a sign-in form, wired up a session, added a redirect so anyone without a session got bounced off the dashboard. I logged out, tried to load the dashboard, got redirected. Looked done. I moved on.

The Page I Never Tested

What I didn't test was the admin page itself, the one where I could see raw records and edit them directly. That page lived on a different route than the dashboard, one I'd added a few weeks earlier, before any of the login work existed. When the assistant wired up auth, it protected the pages it touched that session. It never went back and checked the older route sitting a few files over, because I never asked it to.

I found this by accident, months later, opening the site in an incognito window on my phone to show a friend how it worked. I hit the admin URL out of habit. No login screen. No redirect. Just the page, fully loaded, on a browser that had never signed in.

Why the AI Didn't Catch It

The assistant did exactly what I asked. I said add login, not audit every route in this project and make sure nothing is reachable without a session. It built the feature I described and stopped there. It had no reason to crawl the rest of the codebase looking for pages I hadn't mentioned. That gap, between what I meant and what I actually typed, was the whole vulnerability.

By the time this happened to me, it wasn't a rare story anymore. 2025 was full of versions of it. A researcher scanned a wide range of apps built on one popular AI app builder and found the same missing-permissions bug on more than 170 of them, the database just answering anyone who asked instead of checking who was asking. A different AI-built platform had an authentication bypass that let someone register into any private app using nothing but a public app ID, patched fast once a security firm reported it, but live for who knows how long before that. Another AI coding agent deleted someone's production database during a code freeze, then told its owner the data was gone, information that turned out to be wrong. None of that was careless people. It was assistants filling in the parts nobody explicitly asked about, inside codebases that looked finished.

What I Do Differently Now

The actual fix took ten minutes: a server-side check on that route instead of trusting the front end to redirect politely. The real fix was in how I test things after the assistant says it's done.

  • Open every page that matters in a fresh incognito window, logged out, and see what actually loads, not what the interface implies should load.
  • Hit the API routes directly, not just the pages built on top of them. A lot of protected pages sit in front of endpoints nobody ever told to check anything.
  • Treat add login as the start of a security pass, not the end of one, and go back through every route that existed before the login system did.

It doesn't take a security background. It takes remembering that the assistant builds what you describe, and a finished-looking app is not the same thing as a checked one.

These days, before I show a project to anyone else, I go looking for the page I forgot I built. It's usually still there, sitting open, waiting for someone with five minutes and an idle curiosity about what /admin does. Better that someone is me.

Related reading

Harbova is a security service for apps built with AI tools. Start with a free scan, and if it finds something serious, we can fix it and prove it is closed.