June 14, 2026
I Found a High-Severity Bug by Reading a JavaScript File for 10 Minutes
Most of my best findings don’t come from fuzzing, exotic payloads, or chaining ten obscure techniques together. They come from reading…
Alareqi
4 min read
Most of my best findings don't come from fuzzing, exotic payloads, or chaining ten obscure techniques together. They come from reading things other people assumed nobody would ever read.
This is the story of one of those findings — a High severity issue that started with a single JavaScript file, and ended with a CI/CD pipeline credential and a set of SSO-bypass keys sitting in plain sight on a CDN.
I'm keeping the target anonymous here, but the methodology is exactly what I used, and it's repeatable on a huge number of modern web apps.
Where I started
I was doing recon on a target's login flow. Nothing fancy — just opening the browser's network tab and watching what gets loaded when the login page renders.
One of the requests was a large JavaScript bundle pulled straight from the target's CDN. Hundreds of kilobytes, minified, the kind of file most people would glance at and immediately close.
I didn't close it. Instead, I did something I do on almost every target now: I searched the file for the string process.env.
The moment everything changed
The search returned a huge object — what was essentially a snapshot of the build server's environment variables, baked directly into the client-side bundle at build time.
Sitting inside that object were things that had absolutely no business being in a file served to anonymous visitors:
- A CI/CD agent access token — the kind of credential a build agent uses to authenticate to the CI platform itself
- Multiple "invitation keys" for an internal analytics/data platform — keys that let someone join a workspace without going through the company's SSO
- An internal git repository URL
- The email addresses of the engineers and service accounts involved in the build
None of this is supposed to be public. All of it was sitting in a file anyone could download with a single HTTP request.
Why this happens (and why it's so common)
If you've never touched a frontend build pipeline, here's the short version.
Tools like Webpack support a feature that lets you reference environment variables in your source code, and have the bundler swap them out for literal values at build time. Something like:
const analyticsKey = process.env.SOME_KEY;const analyticsKey = process.env.SOME_KEY;becomes, after the build:
const analyticsKey = "the-actual-value";const analyticsKey = "the-actual-value";This is incredibly convenient — and incredibly dangerous if the build environment has all of its secrets loaded as environment variables (which is normal for CI systems) and the build config doesn't carefully restrict which variables are allowed to be injected.
The result: every secret available to the build process can end up hardcoded into a file that gets pushed to a public CDN.
Making sure it wasn't noise
Finding a string that looks like a token is one thing. Proving it's a real, currently-meaningful credential is another — and this is the step a lot of people skip.
I took the CI/CD agent token and sent it to the relevant platform's own authentication endpoint. The response wasn't a generic "bad request" — it was a response that only makes sense if the platform recognized the format of the token and then rejected it as invalid (i.e., "I understand what this is, and it's not currently valid"), rather than "I have no idea what this string is."
That distinction matters. It's the difference between "this might be a real credential" and "this platform's own systems confirm this is a real credential, just not a live one anymore."
I also went back and checked an older release of the same bundle. Same categories of secrets. Different values. That told me this wasn't a one-time accident — it was a pattern baked into every single build.
Mapping out what an attacker could actually do
This is the part that turns "exposed secret" into "High severity finding," and it's where a lot of reports fall flat. Here's how I broke it down:
The CI/CD agent token — this isn't a key the application needs to function. It's a credential that lets an agent authenticate to the CI platform. With it, an attacker could:
- Register a rogue agent and start receiving real CI jobs
- Use that agent to read secrets from other pipeline jobs it's authorized for — which could include cloud credentials, deployment keys, database connection strings
- Tamper with build output before it's deployed
- Trigger builds that push attacker-controlled code to production
The workspace invitation keys — these are admin-level keys meant to let someone join an internal workspace without going through the company's normal SSO/identity provider. With one of these, an attacker could:
- Create an account inside the company's internal analytics workspace, bypassing SSO entirely
- View connected data sources, configurations, and pipeline setups
- Potentially pivot from a lower-privilege environment (dev/staging) toward production
I also noticed details in the same bundle that hinted at a separate supply-chain angle — but that's a story for another post.
When triage pushes back
My first response from the triage team was something every bug hunter has heard before: "leaking keys doesn't necessarily result in a security impact — can you clarify what an attacker could actually do?"
This is a completely fair question, and honestly, a good filter — a lot of "secret exposure" reports really are just public API keys that are meant to be public.
So instead of arguing, I rewrote the impact section credential-by-credential:
- For each secret, I explained what category of credential it was (CI agent token vs. SSO-bypass invitation key vs. a normal client-side analytics ID)
- For each one, I described the specific actions an attacker could take, step by step
- I included the verification evidence showing the token was real (the API's "recognized but invalid" response)
- I tied it together into a chain: leaked credential → CI pipeline access → ability to influence what gets deployed to production
The report went from "Needs more info" back to fully validated, and was rated High.
Try this yourself
Here's the actual process, condensed:
- Pull production JS bundles. Open dev tools, watch the network tab on key pages (login, dashboard, checkout), and download the larger bundles — or grab them directly from the CDN paths you see referenced.
- Grep for environment injection patterns. Search for
process.env,REACT_APP_,NEXT_PUBLIC_,VITE_, or just scan for blocks ofUPPER_SNAKE_CASE: "value"pairs — that's almost always a sign of build-time variable injection. - Look for things that don't belong on the client. Internal URLs, CI/CD platform tokens, infrastructure hostnames, employee emails, anything that reads like backend tooling rather than frontend config.
- Verify before you report. Hit the relevant platform's own API with the credential. A response that says "I recognize this format but it's invalid" is very different from "this string means nothing to me."
- Check multiple versions. If you can access older bundle versions, check whether the same categories of secrets appear with different values. That turns "a mistake" into "a systemic pipeline issue" — which is a much stronger report.
- Write impact in terms of attacker actions, not just exposure. "This token was exposed" is weak. "With this token, an attacker can do X, Y, and Z" is what gets reports validated.
This whole finding came from reading one file most people would never open. The bugs that pay the most aren't always the hardest to find — sometimes they're just the ones nobody bothered to look at.
If you want more breakdowns like this, follow along — I write these up as I find them.