Source is the wrong place to look
Your repository is clean and your bundle is not. They are different files, and only one of them is served to your users.
Two files, one of which your users receive
There is a file your team writes, reviews, discusses and stores in version control. There is a different file your users download. On a modern frontend these are not the same file, are not similar files, and in the places that matter most they do not contain the same information.
Almost every assurance practice we have operates on the first one. Code review reads it. Static analysis parses it. Secret scanning searches its history. All of that is worth doing, and none of it makes a statement about the second file, which is the only one a stranger can actually fetch.
The gap between them is not a gap in anybody's diligence. It is a gap in what is being examined.
Where the transformation happens
The second file is produced by a build, and a build is not a copy. It is a program that reads your source, resolves configuration, pulls in code you did not write, and emits something new. Three of the things it does routinely have security consequences.
Build-time substitution
A frontend bundler cannot pass an environment variable to a browser, because a browser has no environment. So it substitutes: it finds the place you referenced the variable and writes the literal value in as a string.
// source
const client = createClient(url, process.env.NEXT_PUBLIC_API_KEY!);
// served
const c=o(u,"EXAMPLE_LITERAL_VALUE_INLINED_AT_BUILD")
The value that appears in the second block existed nowhere in your repository. It came from a .env file that is correctly git-ignored, or from a variable set in your hosting dashboard, and it was written into a file on a CI runner some time after every scan of your source had already passed.
Generated configuration
Builds emit more than transformed source. Manifests, route tables, environment snapshots, source maps that reconstruct your original code with its comments intact. These are generated artifacts, they are frequently served alongside the application, and because they never existed as files anybody wrote, nobody reviews them.
Third-party code you did not write
Your dependencies end up in that bundle, as does anything your tag manager or analytics loader injects at runtime. That code is served from your domain and executes with your page's privileges. Its behaviour can change without you deploying anything.
What this means for each of the three surfaces
The same argument holds wherever the running system knows something the source does not.
- Client bundles. The credential exists only after the build. Reading the repository is the wrong corpus; reading the served chunk is the right one.
- Database policies. A policy's text is a claim about behaviour. What a request actually returns depends on that policy combined with every other policy on the table, the caller's role, and the current schema. Only the request answers the question.
- Payment ledgers. Your code describes what should happen on a refund. The ledger records what did. When they disagree, the ledger is right, and it disagrees silently.
In all three cases the source is an honest description of intent, written by careful people, that has diverged from the deployed result — not through error, but because a transformation happened between the two.
Your repository is clean. Your bundle is not. Those are different files.
None of this is an argument against reviewing source, and I would be suspicious of anyone who made one. Review catches things nothing else catches. It simply cannot catch a value that does not exist yet, and no amount of additional care applied to the first file will reveal what is in the second.
The correction is unglamorous: look at the artifact. Fetch the chunk. Make the anonymous request. Pull the balance transactions. Each of those takes minutes, each answers a question review structurally cannot, and each is the kind of thing that is easy to do once and easy to never do again — which is the actual problem, and a different post.
Common questions
Does this mean my CI secret scanner is useless?
No, and it is important to be precise here. It covers a different surface, and it covers it well — committed credentials are a real failure mode and finding them early is worth a great deal. It reports nothing on this class of leak because there is nothing in the repository to report. A green scan is an accurate statement about the repository, and the mistake is reading it as a statement about the deployed application.
Can I not just check the build output in CI?
You can, and it is a genuine improvement — grepping your build artifacts before deploy catches a lot. Two caveats. The artifact your CI produces is not always byte-identical to what your CDN serves, particularly where edge transforms, injected scripts or platform-added code are involved. And a check that runs at build time says nothing about the database policy that changed yesterday or the refund that was issued this morning. Build-output scanning is one instance of the principle, not the whole of it.
If the build creates the problem, is the build the thing to fix?
Sometimes, and where it is, that is the best available fix — moving a call server-side means the value never enters the bundle at all. But the build is behaving as documented. Inlining a prefixed variable is intended behaviour that thousands of applications depend on. The durable answer is not to distrust your build; it is to look at what it produced, on the assumption that you will occasionally ask it to do something you did not mean.