It rendered. The form took an email, the QR code scanned, the whole thing sat on a booth screen and looked exactly like a product. It was also handing its own API key to anyone who opened the page source.
I'd built it fast, a lead-capture tool for a conference booth, the kind of thing that has to exist by a date and look finished in a room full of people who won't look twice. Scan the code, drop your email, walk away. It worked on my machine. It worked on the test link. Every surface I checked from told me it was done.
The audit told me something else.
The key was exposed through a NEXT_PUBLIC_ variable. That prefix is an instruction. It tells the framework: take this value and ship it to the browser, bake it into the bundle every visitor downloads. It exists for the things that are supposed to be public, the ones you'd write on a whiteboard. I had used it for a credential.
That's the trap in the naming. NEXT_PUBLIC_ doesn't warn you. It does exactly what it says, correctly and without comment, and the thing it does correctly is publish your secret. The variable worked. The key was live. The tool functioned end to end. Nothing failed, which is precisely why nothing flagged it.
Underneath that, the same pattern repeated. A storage URL exposed client-side. No rate limiting, so the endpoint would take as many requests as anyone cared to send it. CORS configured in a way that would either block the real traffic or wave through traffic it shouldn't. Four separate holes, none of them throwing an error, all of them in a tool that looked complete.
There was one more failure, and it's the one I think about most, because it's the one no audit tool catches.
The QR code pointed through an external service, a redirect, a shortener, a dependency I'd added without thinking of it as a dependency. It resolved instantly on my desk. It would also resolve instantly at an empty booth. The place it would not resolve was a conference floor at peak hours, on venue WiFi shared by a few thousand phones all fighting for the same congested band. The one condition the tool was built for was the exact condition it hadn't been tested in.
The QR code was the only failure I could see with my eyes. It was also the least dangerous one. The leaked key was invisible and catastrophic; the dead QR code was visible and merely embarrassing. I'd have caught the embarrassing one live, at the booth, in front of people. I would not have caught the catastrophic one at all.
The fix wasn't clever. The key moved to the server, where it belonged, behind an endpoint that never hands it to the browser. Rate limiting went on. CORS got scoped to the one origin that needed it. The external redirect came out; the QR code pointed at something I controlled.
None of that is hard. All of it is the kind of work that gets skipped when the deadline is the thing being optimized and the tool already looks done. The demo conditions, my machine, the test link, the empty room, hid every failure that production would have surfaced. And production, in this case, was a crowded floor with a live key in every visitor's browser.
The tool that looks finished and the tool that is finished are two different tools. The gap between them is invisible from the angle you build at. You have to go stand somewhere else to see it.
[SOURCED] Booth lead-capture tool with an API key exposed via NEXT_PUBLIC_, an exposed storage URL, absent rate limiting, CORS misconfiguration, and a QR code dependent on an external service that fails on congested venue WiFi; caught in audit and rebuilt server-side.
[GENERATED] NEXT_PUBLIC_ framework behavior described generically (Next.js public-env convention), standard, not proprietary.
• No conference, client, or attendee detail included, by rule.
• Whether the tool ever went live in the vulnerable state before the audit is not asserted, the essay treats it as caught before use.