Est.

Every Pull Request Was Running Against Production Data

Preview environments were accidentally running live production data for every code change.

· 2 min read
Features · September 16, 2026 · 2 min read · 502 words
# Every Pull Request Was Running Against Production Data I found this one by accident, checking a deploy platform's environment settings for an unrelated reason. Every preview environment the platform spun up for a pull request was seeded by cloning the live production environment's variables — including the production database connection string. Every PR, from every contributor, for as long as the project had existed, had been running against the real database. ## Why nobody had noticed Nothing about this failed loudly. Preview environments worked. Features demoed correctly in PR previews because they were reading and writing real data, which made them look more correct, not less. The danger wasn't a crash; it was that anyone testing a delete, a bulk update, or a migration-adjacent change against a preview URL was doing it directly against production, believing they were in a sandbox. It's the kind of gap that only becomes visible in the aftermath of an incident, when someone finally asks "wait, which database was that preview pointed at?" This is a structural risk that specifically doesn't show up in a code review, because the code is fine — the vulnerability lives entirely in platform configuration, one layer removed from anything a pull request diff would surface. Diligence that only reads application code will miss it every time. ## Closing the gap without breaking the workflow The fix used the database provider's own branching primitive: on PR open, provision an isolated, copy-on-write database branch and override the PR environment's connection string to point at it; on PR close, tear the branch down. Preview environments kept working exactly as before from a developer's point of view — same URLs, same behavior — but each one now had its own disposable data, cloned cheaply rather than shared dangerously. The rollout was deliberately feature-flagged rather than enabled outright, because a fix like this needs its prerequisites (API credentials, provider setup) in place before it can run, and a naive rollout that assumes they exist fails loudly for everyone the moment it ships. Skipping cleanly when a prerequisite is missing is a small design choice that matters a lot in practice — a security fix that turns a soft gap into a hard outage on day one gets reverted, and the org is back to the original risk with less appetite to try again. ## The audit question this changes I now ask a specific question early in any technical assessment: when this project spins up a preview or staging environment, where does its data actually come from? Not "is there a staging environment" — most teams say yes to that reflexively — but "what populates it, and is that population step isolated from production or does it clone it." The answer is usually assumed rather than verified, by the same team that built the system, because the platform's defaults are invisible until someone goes looking. It's a five-minute check with a blast radius that, left unchecked, is every single deploy the project has ever previewed.

More in Features