ProofScan

Scanners guess. ProofScan proves.

A web vulnerability scanner that tests every suspicious finding before it reports it, and keeps the evidence.

Replay a real scan Sample PDF report Source on GitHub
ProofScan replaying a scan of DVWA: 12 suspicious, 6 proved real, 6 proved false and thrown out

The problem

Security scanners report a lot of things that are not real. Someone then has to check every alert by hand, which is the slow part of a security test. ProofScan does that checking itself. It looks for SQL injection and cross-site scripting (XSS), and every candidate gets a second, active test that tries to prove it. Only what it can prove goes in the report.

How it proves things

True/false test

Send an always-true and an always-false condition that differ in nothing else. If the pages differ by more than the page differs from itself, the database ran our input.

Timing test

For pages that never change. Two inputs, a sleep behind a true or a false condition. Confirmed only if the true side is slower every single time.

Real browser

Load the page in headless Chromium. The script has to hand back a random token only it knows. Coming back in the page is not enough, it has to run.

Results against OWASP ZAP

On DVWA, a deliberately vulnerable app I did not write, scored on SQL injection and XSS against a hand-written answer key:

AlertsCorrectFalse alarmsPrecisionRecall
ProofScan, verification off12660.500.86
ProofScan, verification on6601.000.86
OWASP ZAP 2.177610.860.86

The same numbers came out of four ProofScan scans and two ZAP scans, six weeks apart. ZAP also checks around a hundred kinds of problem that ProofScan does not, so this is a trade of coverage for certainty, not a claim that ProofScan beats ZAP. Everyone missed DOM-based XSS.

The case that shows the idea

On DVWA's CSP page our input comes back in the page completely unescaped. ZAP reports it as XSS, High risk. But the page sends a Content-Security-Policy header, so the browser refuses to run the script. ProofScan opened it in a real browser, five payloads ran zero times, and it threw the finding out. Reading the response cannot tell "came back" from "ran". Running it can.

ProofScan's card for DVWA's CSP page: thrown out, none of the 5 payloads ran
Thrown out: the page looks normal because the script never ran.

Safe by design

Built with

Python, Playwright (headless Chromium), Flask, SQLite and Docker. CVSS v3.1 scoring with CWE and OWASP Top 10 mapping, PDF reports, and 183 automated tests.