a detector accuracy audit surfaced two classes of bug in the framework
detectors.
bare-brand header false positives: header-only signatures matched a
brand name as a substring across every header name and value, so a
detector fired on any response that merely referenced the brand (a
vendor cdn named in a link or csp value, a cookie sharing the prefix).
add an optional Header field to Signature that scopes a header-only
match to one named header's value, and apply it (or a structural
anchor) per detector:
- express: "Express" scoped to x-powered-by, was firing on an
express_checkout cookie.
- flask: "Werkzeug" scoped to the server header.
- symfony: dropped the bare "symfony" word (symfony sets no such
header, it fired on symfony.com links); the x-debug-token header is
the marker.
- shopify: key on the x-shopify response headers instead of the bare
"Shopify" word, which fired on a cdn.shopify.com link.
- remix: dropped the bare "remix"/"_remix" substrings that fired on a
track_remix.mp3 asset; window.__remixContext is the definitive
marker.
- spring boot: anchor the whitelabel title in its h1 tag context so a
tutorial discussing the error does not fire.
the gin and fastapi detectors are removed: gin keyed on the
"gin-gonic" import-path string (appears in tutorials, never in a real
gin response) and fastapi on bare words matching the projects' doc
domains. neither framework advertises itself in a response header or a
non-prose body marker, so there is no clean passive signal to anchor
on.
version mis-extraction: drop the low-confidence ".*?" version
fallbacks (rails, django, laravel, spring), whose unbounded gap
grabbed the first version-shaped number after the framework word and
reported an unrelated asset's cache-buster when no real version was
present. let isValidVersionString accept a single integer so a bare
major such as drupal's "Drupal 10" is no longer rejected as "unknown".
each false positive and version bug is covered by a regression test.
rename the go module path from github.com/dropalldatabases/sif to
github.com/vmfunc/sif across go.mod, all imports, the golangci exclude
list, release install docs and docs. pure string rename, no logic change.
replace bare gin/api/cake/svelte/ember/backbone/meteor substrings with
specific markers (Backbone.Model, ember-application, __meteor_runtime_config__,
CAKEPHP cookie, svelte/internal) so prose and CORS headers stop matching.
adds paired false-positive/positive coverage per framework.
the asp.net detector carried {Pattern: "X-Powered-By: ASP.NET", HeaderOnly:
true}, but containsHeader matches a signature against each header name and each
value separately, never against a joined "name: value" string. so that pattern
could never match anything. it only added its 0.4 to the detector's total
weight, diluting every real signal: a genuine response (an X-AspNetMvc-Version
header, an X-Powered-By: ASP.NET header, an .aspx link) scored 1.1/3.8 = 0.47,
just under the 0.5 threshold, and went undetected.
the live "ASP.NET" header signature already matches the X-Powered-By value, so
removing the dead one loses no coverage and lifts that same response to
1.1/3.4 = 0.56. adds a regression test for it.
the ghost detector keyed on the bare "ghost-" body substring, which fires on
any page using the common "ghost-button" or skeleton-loader CSS class (e.g. a
WordPress theme), scoring 0.65 and reporting it as Ghost CMS. key on the
canonical `<meta name="generator" content="Ghost` tag instead, matching the
existing astro detector. the /ghost/api/ path and Ghost header markers are
unchanged.
a ghost site that emits neither the generator meta nor a /ghost/api/
reference is no longer detected; the Ghost response header alone scores
below the detection floor.
the phoenix and adonis detectors matched bare substrings ("phx-", "phoenix",
"adonis") that fire on unrelated pages: a "phx-" css class on a phoenix,
arizona site, or any markup containing the word "adonis". replace them with
markers the frameworks actually emit. phoenix keys on the liveview container
attributes data-phx-main, data-phx-session and data-phx-static; adonis on its
default adonis-session cookie.
this narrows detection: plain (non-liveview) phoenix and session-less adonis
apis are no longer matched. the markers we now key on (liveview's container
attributes, adonis's default session cookie) are ones ordinary prose cannot
forge. each detector gains a true-positive test and a false-positive tripwire.
rolls the (c) 2022-2025 banner to 2022-2026 across all go files, the
startup banner in sif.go, and the header-check workflow's expected
format. comment-only, nothing else changes.