v0.0.156
Released Nov 1, 2026
Release Notes
Site integrity is harder to talk around: integrity/brand-impersonation no longer spares a sign-in link to an identity broker's authorize URL because its query names a provider (the tenant must be the site's own), ranks controls by the destination as a browser reads it, and integrity/fake-auth-overlay reads the modern viewport units and tokenises a style the way a browser does, so a string, comment or escape no longer hides the geometry. The JSON report (schema 1.5) names the rules that ran, and --include-pages lists the URLs that never answered with a fixed reason code. Technology detection finds Microsoft Clarity's loader inside a first-party bundle and Railway behind server: railway-edge.
Added
- Microsoft Clarity is detected from its loader inside a first-party bundle. The standard snippet's
t.src="https://www.clarity.ms/tag/"+i(and itssetAttribute("src", ...)and template-literal forms), bundled into a site's own script, now matches as code, with the window around it sent in a capped scan. A bundle that only names the URL in prose, a docs string or a comment does not. Before v0.0.150 a few such installs were found by accident through a whole-text read of the page. (#1488) - The JSON report names the rules that ran, and
--include-pageslists the URLs that never answered.executedRulesis the sorted list of rule ids that produced at least one check that was not skipped on this audit, soissues,passedRulesandskippedCheckscan be checked against it without readingsquirrel.toml; a fully skipped or disabled rule is not listed, and a finding a smart audit carried over from an earlier crawl does not make a rule executed. With--include-pages, a URL the crawl requested but stored no page for (a connection error, a rate-limited request with no stored response, an excluded or out-of-scope URL, one robots.txt blocks) is listed after the crawled pages withoutcomeerrororskippedand areason, inside the 2,000-entry cap.meta.schemaVersionis1.5; both additions are optional. (#1396)
Fixed
railway-appis detected fromserver: railway-edgetoo. TheServersignature matched onlyrailwayandrailway-hikari; Railway's v3 edge proxy sendsrailway-edge(per its changelog), so a custom-domain site served by it went undetected. (#1504)integrity/fake-auth-overlayreads the modern viewport units. A fixed full-screen frame sized withdvh,svh,lvh,dvw,svw,lvw,vmaxorvmin(alone or insidecalc()) was not seen as covering the viewport, while100vhwas. They now count, and a length is read as its own number (1100%is a real, over-full width, not a100%lookalike). Other spellings fill too (100.0%,+100vw,1e2vw, over-full150%,calc(50vw + 50vw),100vi/100vb,100cqw,stretch,-webkit-fill-available), as do the logical inset properties; CSS escapes (1\30 0vw) and comments in a style are undone before the length is read, padding a value past the scan cap counts as filling, never as hiding it, and the CSS is read three ways, a frame being a cover when any of them says so (as a browser tokenises it, with a;,/*or}in a string,url()or block not splitting, commenting or closing anything; with comments dropped and a split on every;; and a plain split on;), so a quote, comment, bracket, escape or newline that one parser reads differently from a browser does not by itself hide a declaration, in a style attribute or in a<style>rule (at-rule preludes,@import "a;b";and[a="{"]selectors are cut past strings too); the old plain split stays one of the readings, so nothing it caught is lost; the evasions left (var(--w),@media/@layerwrappers, nested rules, descendant selectors, external stylesheets, near-full sizes,min-width,transform: scale()) are listed in the rule's docs. (#1496)integrity/brand-impersonationranks a control by the destination as a browser reads it. A link written/\other.example/xor with a tab inside (/<TAB>/other.example/x) is the protocol-relative URL it resolves to, but the ranking read the raw text and treated it as local, so a long label past 256 nodes was neither read in full nor counted as unread. The ranking now uses the same normalised destination as the own-site test. (#1495) The sign-in path is looked for in the first 8,192 characters of the destination (it was 300, on the raw text), the text is computed once per control, and links to other hosts are not moved ahead of other links when the 60,000-control cap cuts (only the read order within the prepared ones).integrity/brand-impersonationno longer spares a sign-in link to a broker's authorize URL on the strength of its path or a hint in it. A "Continue with Google" or "Continue with Microsoft" control to an Auth0, Okta, Cognito, Supabase or Firebase authorize endpoint was treated as a real integration on the path alone, but those hosts let anyone register a tenant, a tenant controls its hosted login page, and the link is written by whoever wrote the page. For Auth0, Okta and Cognito the first host label (the tenant) must now be the audited site's name: exactly (no hint needed), or the name plus a fixed environment suffix (-prod,-dev,-staging,-qaand similar) with the query naming the provider the label does; a free-form suffix (-login,-sso), a deeper label, a look-alike or a name under three letters is not spared. Supabase and Firebase endpoints (no tenant login page) need the named provider. The query of a link is read only for a broker-shaped destination, so long queries on other links cost nothing. A foreign tenant, a bare authorize URL or another provider is reported like any off-brand host (aninfocheck as a single signal). (#1494)
Update to this version
squirrelscan will auto-update, or run this command to update now: