DEV Community

Rxkov
Rxkov

Posted on Originally published at blog.mago.team

Your JS Secret Scanner Is Reading webpack Polyfills

Keyword secret scanners love the word password inside JavaScript. Next.js ships a URL polyfill that parses username and password off every URL. The password is often an empty string. The scanner still screams CRITICAL.

The finding is a parser, not a credential. If the report attributes it to the target, the grade is a lie.

Where the empty password comes from

The WHATWG URL Standard stores userinfo as username and password. new URL("https://example.com/path") has an empty password. Polyfills copy that object into the bundle so old browsers can parse URLs.

Chromium and Node both expose url.password as a string. Empty is valid. A scanner that flags any identifier named password cannot tell a URL field from const password = "hunter2". The second is a secret. The first is the platform.

Next.js has long inlined those polyfills in a polyfills-*.js chunk under /_next/static/chunks/. The minified code still contains the property name password and the helper cannotBeABaseURL. A naive password_in_code rule fires on that chunk for every Next site on the internet.

Google Tag Manager and Shopify pixels produce the same class of hit. A third-party shop page in urlscan mentions the target in a query string. The JS job then "finds" an OAuth client id that belongs to the shop, not the seed domain.

First-party or it does not count

A JS finding is on-target when the script URL is the apex or a subdomain of the seed. app.example.com is in. cdn.shopify.com is out. accounts.google.com is out.

def is_first_party(script_host: str, apex: str) -> bool:
    host = script_host.lower().rstrip(".")
    root = apex.lower().rstrip(".")
    return host == root or host.endswith("." + root)
Enter fullscreen mode Exit fullscreen mode

Drop the finding when every extracted URL in the blob sits off-apex. Keep it when the bundle is https://example.com/_next/static/chunks/main-*.js and the secret is a real AKIA or sk_live_ value.

Polyfill markers that have no business in a customer HUD:

cannotBeABaseURL
password:""
password\":\"\"
Enter fullscreen mode Exit fullscreen mode

Those strings are URL parser furniture. They are not a dumped admin password.

What the HUD should show instead

A useful JS section lists endpoints and real secrets on first-party hosts.

  • /api/v1/forms on https://example.com is an endpoint. INFO.
  • AKIA plus 16 more chars in https://example.com/static/app.js is a key. HIGH or CRITICAL after a shape check.
  • password="" in polyfills-*.js is noise. Delete it.

mago.team js_analyzer follows only HTTP 200 origins on the scanned selector. Off-target urlscan neighbours do not get queued. The report builder then drops polyfill and off-apex js_secret rows so they cannot tank the aggregate score.

A recon grade of A+ next to a page of CRITICAL JS hits is how you lose the operator. The polyfill was never a credential. The empty password was never a dump.

How to verify on one host

Fetch the homepage. Collect script src values. Keep hosts on the apex. Scan those bodies for key shapes, not the word password.

AKIA[0-9A-Z]{16}
sk_live_[0-9a-zA-Z]{8,}
-----BEGIN (RSA )?PRIVATE KEY-----
Enter fullscreen mode Exit fullscreen mode

If the only hit is password next to cannotBeABaseURL, the scanner is reading the platform. Switch the rule. Paste the same host into mago.team and compare the JS section. The pipeline should stay quiet unless a first-party bundle leaked a key.

Why this wrecks a domain grade

A typical Next marketing site has one polyfill chunk and a GTM snippet. A keyword scanner emits 20 CRITICAL js_secret rows. The aggregate score falls off a cliff. The operator sees "compromised." The page is a stock create-next-app output.

mago.team dropped those rows after they showed up as CRITICAL on properties that were not breached. The filter lives in the report builder. New scans do not store the polyfill hit. Old reports still show it until a rescan.

urlscan adds a second lie. A neighbour page with a 200 can mention the seed in a Google tag. If the follow-up JS job uses that URL as origin, Shopify pixels and Keycloak query strings land in the customer HUD. Restrict follow-ups to HTTP 200 on the seed apex and its subdomains.

Header-grade D and DMARC p=none are real. They should move the ring. A polyfill password should not. Mix them and nobody trusts the number.

The test is simple. If the same CRITICAL fires on every Next.js site you scan, it is the framework. Delete the rule. Keep the AKIA rule. Keep the first-party host check. Then the JS section is short enough to read.

Top comments (0)