v0.0.159
Released Nov 2, 2026
Release Notes
security/leaked-secrets is more precise and harder to talk around: an admin-named hosted-search key reports at high with a hint (William's #1523 for #1515, with an overlapping maintainer draft, #1524, folded in), a header-only Bearer JWT, a JWT-shaped string that does not decode and an AMD or RequireJS module path are no longer reported as credentials, and a real token with a missing alg, an oversized part or a decoy in front still reports. The integrity rules count an unread control once, read a style attribute and a CSS rule to larger bounds, say so when a rule is too large to read, and resolve a relative link by the page's first <base href> as a browser does.
Fixed
security/leaked-secretsno longer reports an AMD / RequireJS module path whose words are all known as a credential. A module path such asMagento_Customer/js/change-email-passwordunder a credential-named key was reported as a generic secret. A value of segments joined by/is now a name when every word (at most three per segment, camelCase parts and plurals included) is in a list of module-path words, it has aVendor_Modulehead or ajssegment, and no segment has more than two digits or three capitals. A path with a word outside the list reports as before, so some real module paths still report; a drawn run of letters is not a word, so random values with a/still report. Trade-off: a passphrase made only of listed words in that shape can be suppressed. (#1292)security/leaked-secretsno longer reports a header-only JWT afterBearer.Bearer eyJhbGciOiJIUzI1NiIs, the header segment of a JWT with no dot, payload or signature, was reported as a medium bearer token. It is dropped only when the whole value decodes to a complete JOSE header (a JSON object with analgand only JOSE header keys), or is a short truncated one (64 characters or fewer, cut mid-JSON, opening withalg,typ,kidorcty), and the text after it does not continue a token. An opaque JSON bearer value that merely opens with one of those keys, a JWT written with a%2E, space, comma or escaped separator, and a fullBearer <JWT>still report. (#1227)security/leaked-secretsstops reporting strings that only look like a JWT. AJSON Web Tokenmatch was kept as a generic JWT-shaped string at medium when it did not decode. It is now dropped only on proof: a header or payload within the 8,192-character read bound that is not a JSON object (garbage, truncated, trailing bytes, an array, a string, a number ornull; a header within the bound that is not valid JSON counts as proof, one past the bound does not), or a header object with no stringalgover a payload that is only a plain generic token. A part past 8,192 characters, nested too deeply to parse or empty still reports, and a header with no stringalgkeeps the classification its payload earns (service_role, an admin scope, Supabase, Hygraph, Shopify). Known limit (#1530): two decoyeyJ…segments in a row before a real token consume its payload, and the match is dropped; one decoy is handled. (#1283)- The integrity rules no longer pass three bounds in silence. A hidden decoy after more than 8,192 characters of
styleattribute was read as visible and broke the label's phrase; a style attribute is now read to 1 MB (once per element), and a control with a longer one is counted incontrolsUnread. A CSS rule with a body over 4,000 characters or a selector over 300 was skipped whole, hiding an overlay rule behind cheap padding; rules are now read up to 256 KB and a 2,048-character selector, and a larger rule that could match an iframe on the page makes the CSScssTruncated. A link or form resolved against a<base href>on another host is now judged by that host (and a relative iframesrcresolves against it), where it was judged as the page's own site; a selector list is read per part (a list over 2,048 characters of short parts no longer hides the matching one), an oversized part, prelude or hidden-class rule givescssTruncatedorhiddenCssTruncated, links are ranked as off-site under a moved base, a<base>inside svg, math, noscript or template is ignored (one inside<foreignObject>is honoured), an empty linkhrefgoes to the base, and the base is found once per document in one linear pass with no depth bound (a page of 30,000 iframes or 80,000 nested<base>elements stays linear, and nesting depth never decides which base wins). (#1423) integrity/brand-impersonationcounts a control once incontrolsUnread. A control that hit more than one bound (an attribute over 16,000 characters, more cue windows than the cap, a text read cut at its visit allowance) was counted once for its attributes and again for its text read, sodetails.controlsUnreadcould exceed the page's controls. Each control now counts at most once; controls cut by the prepared-controls cap or the logo-alt cap are still counted, and templates past the limit stay intemplatesUnread. (#1491)security/leaked-secretsdistinguishes admin-named hosted-search keys from search-only keys. A 32-character value (Algolia and Typesense shape) undersearch_admin_api_key,adminApiKeyoradmin_api_keyreports at high, and amaster_api_keyname at any length;search_api_keystays medium with the search-only hint. MeilisearchmasterKeyreports at high andsearchKeyat medium with the hint, only whenmeiliappears in the name or in the 120 characters before it. A placeholder such asYOUR_MASTER_KEY_GOES_HEREis not reported, and a one-wordsearch_apikeyname is read as before. See leaked-secrets. (#1515)
Update to this version
squirrelscan will auto-update, or run this command to update now: