Security Scanner

Findings with evidence, not guesses.

Header, TLS, cookie, secret-exposure, and information-disclosure rules run against every page the crawler reaches. Each finding arrives with the request and response that produced it, a severity, an honest confidence level, and the specific change that fixes it.

Rule categories
6
Required for every finding
Evidence
Evidence records
Immutable
Requests that change state
Never
A real finding

Severity means nothing without the evidence.

Pick any finding and the exact captured response is right there: headers, cookie flags, the matched line, the certificate. Nothing is asserted that the scanner can't show you.

Findingsscan #4182 · 5 open
highConfirmedheaders/csp

Content-Security-Policy header missing

Response headers
HTTP/1.1 200 OK
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
content-security-policy: (not present)
server: nginx/1.24.0
Why it matters: Without a policy, any injected script executes with full page privileges: the difference between a contained XSS and a session takeover.
Remediation: Start in report-only mode with default-src 'self', collect violations for a week, then enforce.
How it behaves

A scanner you can hand to an engineer

The failure mode of most scanners isn't missing a bug. It's a hundred findings nobody trusts. These rules are built against the opposite constraint.

Never confirmed without proof

Every rule returns its finding through one shared builder that requires evidence, an affected URL, and a plain-language explanation. A rule that can't produce evidence reports lower confidence. It doesn't upgrade a guess.

Read-only by construction

No rule may send a request with a state-changing body, attempt authentication bypass, or guess credentials. That's enforced by the rule interface itself, not left to each rule's author to remember.

Written in plain language

Each finding carries what it is, why it matters to the business, and a fix example, so the person who has to change the config doesn't need to translate a CVE reference first.

Continuous, not one-off

Scans re-run and diff against the previous result. New, still-present, and resolved findings are tracked separately, so progress is visible instead of restarting at zero each time.

A failed scan is never 'clean'

If a scan can't fetch pages it's marked failed, not passed. Treating 'couldn't check' as 'nothing found' is the single most dangerous bug a scanner can have, so it's ruled out by design.

It learns your false positives

Mark a finding false-positive and confidence for that rule drops for that project only. The rule keeps running and keeps detecting. It's the label that changes, never the coverage.

Rule coverage

What every scan checks

Each category is an independent rule module against a shared interface, which is why coverage grows without the existing checks changing behaviour.

Security headers

CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy, evaluated per page rather than once per site.

csphstsx-frame-options

Cookie flags

Secure, HttpOnly, and SameSite on every cookie the site sets, with the raw Set-Cookie header kept as evidence.

SecureHttpOnlySameSite

TLS configuration

Certificate validity and expiry plus negotiated protocol version, captured as history so renewals and regressions are both visible.

validToprotocolissuer

Exposed secrets

Stripe, AWS, GitHub, Slack, and Google keys, JWTs, PEM private keys, service-account JSON, connection strings, and bearer tokens, found in HTML, headers, and same-origin JavaScript.

sk_liveAKIA-----BEGIN

Information disclosure

Exposed .git and .env files, backups, source maps, directory listings, verbose error pages, and version-leaking server headers.

.git.envautoindex

Technology fingerprinting

Frameworks, CDNs, and third-party services identified from headers, HTML signatures, and known JS globals, which is the context for every other finding.

headerssignaturesjs-globals
How it works

What happens when a scan runs

Crawl, apply rules, capture evidence, diff against last time. Each stage is a separate job, so a slow one never blocks the rest.

  1. 1

    The crawler collects pages, respectfully

    Breadth-first from your verified domain at roughly one request per second, honouring robots.txt, your depth and page limits, and the included and excluded paths configured on the project.

  2. 2

    Rule modules run in parallel

    Header, cookie, TLS, secret-detection, disclosure, and fingerprinting rules each run independently against the crawled pages under bounded worker concurrency, so one slow rule doesn't hold up the scan.

  3. 3

    Evidence is redacted, hashed, and stored

    Anything that could contain a secret goes through the redaction helper before it reaches storage. Each evidence row keeps a SHA-256 of the original value and the scanner version that produced it, and is never updated or deleted.

  4. 4

    The result is diffed against the last scan

    New findings, resolved findings, and score changes are computed against the previous completed scan, and only when one exists, so a first scan is recorded as a baseline rather than a wall of 'new'.

  5. 5

    Critical findings open incidents

    A newly introduced critical or high finding opens an Incident with its own status timeline, so remediation is tracked as work rather than as a row in a list someone has to notice.

Security Scanner, answered.

It can't, by construction. No rule may send a request with a state-changing body, attempt authentication bypass, or guess credentials. Those constraints live in the rule interface every module implements, not in each rule's own code. The crawler is also rate-limited per hostname with deliberately conservative defaults.

Run a scan and see the evidence.

Verify a domain, run the first scan, and read the findings with their captured responses attached.