squirrelscan
GitHub

Template discontinuity: a page that is not on your theme

An injected standalone page loads none of your site's CSS, hosts or chrome. squirrel fingerprints every page and scores it against the site baseline.

What template discontinuity is

Most pages a CMS renders share theme markers: the same stylesheets, the same asset hosts, overlapping body classes, a navigation element and a footer. It is not a rule. WordPress supports per-page templates and page-specific body classes, and injected content can also inherit the theme it was injected into. What the pattern catches is the standalone case, a page written to look like something else that loads none of the site’s own assets.

Measuring the gap turns “this page looks wrong” into a number. A page can legitimately be off-theme, a bare landing page or a hosted form, so a low score on its own is a review item rather than a verdict.

What squirrel checks

The rule is site-wide. It fingerprints each page on five theme markers: stylesheet hrefs, asset hostnames from link, script and img references including same-origin ones, body class tokens, CSS custom-property names declared in <style> elements or in an inline style on <html> or <body>, and whether the page matches nav, [role='navigation'] and footer, [role='contentinfo'].

The baseline is not a cluster. Each marker is tallied across every fingerprint and kept when it appears on at least max(2, ceil(n / 2)) pages. Similarity is then a weighted sum: Jaccard overlap for stylesheets at 0.35, asset hosts at 0.25, body classes at 0.15 and CSS variables at 0.1, plus a chrome term at 0.15 that is the average of two boolean matches on nav and footer.

  • Skipped when the crawl produced fewer pages than minPages. Message: Need >=N pages to establish a template baseline.
  • Skipped when too few pages had a parseable document. Message: Too few parseable pages for a template baseline.
  • Skipped when the baseline has no shared stylesheets and no shared asset hosts, so there is no theme to diverge from. Message: No shared template baseline detected across the site.
  • Pass when every page scores at or above the threshold. Message: All pages share the site's common template.
  • template-discontinuity warns for below-threshold pages that carry at least one page-level integrity signal and load nothing the rest of the site loads. Message: N off-template page(s) share none of the site's assets and carry a page-level integrity signal, listing up to five as /path (sim S).
  • A below-threshold page is never escalated when it loads one of the site’s own stylesheets, or loads a stylesheet or a script from a host that serves a stylesheet, script or image on a majority of the crawled pages. An injected standalone page brings its own everything; a signed-out account view pulling the site’s CSS bundle is the site’s own page, however little of the theme it renders.
  • Three things deliberately do not count as the site’s assets. A link that is not a stylesheet, so a canonical, an icon, a preconnect, a dns-prefetch or an alternate pointing at the site proves nothing about who rendered the page. A shared public host: fonts.googleapis.com, fonts.gstatic.com, ajax.googleapis.com, cdnjs.cloudflare.com, and any subdomain of jsdelivr.net or unpkg.com, since every site on the web can load those. And an image on its own, because a standalone page can hotlink a logo.
  • Nothing is escalated when the crawl stopped at its page limit and the baseline came from fewer than minBaselinePagesWhenCapped pages. A capped crawl saw the first N pages of the site, not the site, so its baseline can be one section’s template and everything outside that section looks foreign. Those pages are still reported for review, and the review check’s details carry escalationWithheld: capped_crawl_small_baseline. Raising the page limit is what changes the verdict.
  • template-discontinuity-review reports info for below-threshold pages that were not escalated. Message: N page(s) diverge from the site template (review).

Severity is warning, weight 6.

Stylesheets, scripts, images and <style> elements inside <noscript> are left out of the fingerprint, because a browser with scripting enabled never loads them. See content inside noscript.

How to fix it

Open the listed pages and compare them with a normal page from the same site. Most of the time the answer is that you published it: a campaign landing page, a signed-out or empty state, a checkout step. If a page is yours, load the shared stylesheet and the site chrome on it, which also fixes the inconsistency a visitor would notice and stops the page being reported. Only if you did not publish it does the compromise reading apply, and then remove it, audit recently modified files and read the access logs.

A marketing landing page that deliberately ships its own CSS scores low and is reported for review. A site with no shared stylesheets or asset hosts at all produces a skip instead, because there is no baseline to measure against. Lower similarityThreshold, or disable the rule, when off-template pages are the design.

Rule IDintegrity/template-discontinuity
CategorySite Integrity
ScopeSite-wide
Severitywarning
Weight6/10

Options

OptionTypeDefaultDescription
minPagesinteger, 3 or more4Minimum pages needed to establish a reliable baseline
similarityThresholdnumber, 0 to 10.2Pages below this similarity to the baseline are flagged
minBaselinePagesWhenCappedinteger, 0 or more20When the crawl stopped at its page limit, escalate only if the baseline was built from at least this many pages; below it, outliers are still reported for review

Configuration example

[rule_options."integrity/template-discontinuity"]
minPages = 10
similarityThreshold = 0.1
minBaselinePagesWhenCapped = 30

Enable / disable

Disable this rule

[rules]
disable = ["integrity/template-discontinuity"]

Disable all Site Integrity rules

[rules]
disable = ["integrity/*"]

Enable only this rule

[rules]
enable = ["integrity/template-discontinuity"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Site Integrity findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.

Glossary: Hacked site signals.

References

Check your site

Run squirrel audit https://example.com and open the Site Integrity section of the report. Each outlier is listed by path with its similarity score. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close