Not a glorious bug, but the fastest fix of the year. Thirty minutes of work, two hours to revocation.
The signal
First reflex on any application: ask for the source maps of the bundles being served.
for f in $(curl -s https://app.target.tld/ | grep -oE '/assets/[^"]+\.js'); do curl -s -o /dev/null -w "%{http_code} $f.map\n" "https://app.target.tld$f.map"done200 /assets/index.9f1c2a.js.map200 /assets/admin.4b77de.js.map404 /assets/vendor.88c01f.js.mapThe second file had no business being there: the admin interface is not meant to be served from the same domain as the customer-facing app.
What was inside
Reconstruction gives the full project tree, the developers’ comments, and two constants that should never have left the repository:
export const INTERNAL = { adminHost: 'ops-████████.internal.target.tld', mailApiKey: 'SG.████████████████████████████', featureFlags: ['billing_v3', 'sso_scim', 'export_full'],};The messaging key was still live - verified with a single read-only call to the provider’s profile endpoint, without sending a single message. The feature flags, meanwhile, shaped the next piece of research: export_full is exactly the route that produced the account takeover two months later.
Takeaways
.js.mapbelongs in the bare minimum checklist, on every bundle, on every deployment.- A source map does not only leak code: it leaks the tree, the comments and the internal names, which steer everything you look at next.
- An exposed key gets verified with the least intrusive call available, never with an action that produces a visible side effect.
Disclosure timeline
- Report sent
- Emergency mitigation key revoked within two hours
- Fix deployed source maps pulled and the pipeline corrected
- Cleared for publication