The problem with finding lists
Classic scanners produce lists of potential vulnerabilities. You read them, you file them, and 30% turn out to be false positives. Everyone's time gets wasted — yours, your client's, the dev team's.
Verify Now is the other half of the workflow. You get a finding. You click Verify. The scanner attempts actual exploitation and tells you whether it worked, with hard evidence.
Canary-based exploit confirmation
The core technique: send something that's obviously not in the app already, look for it to come back. For command injection:
GET /products?category=; echo WISCMD40293517ZZ
→ 200 OK, 22319 bytes
response body contains "WISCMD40293517ZZ"
That string isn't in the product catalog. It isn't in the HTML template. It's only in the response because the backend ran echo WISCMD40293517ZZ as a shell command. Confirmed RCE, 95% confidence.
When canaries don't work: time-based blind
Some apps suppress output. You still get confirmation by timing: inject sleep 5 and see if the response takes 5+ seconds longer than baseline.
Baseline: GET /products?category=Beverages → 312 ms
Test: GET /products?category=; sleep 5 → 5318 ms
delta: +5006 ms → RCE confirmed (blind)
To avoid false positives from network jitter, we require the delta to both exceed the sleep duration minus 500ms margin AND exceed twice the baseline. A slow-but-consistent server doesn't trigger a false positive this way.
SQL injection needs three channels
SQL has more ways to confirm than RCE. The verifier runs all three in order:
- Error-based: Send
'. Match response against 14 RDBMS error signatures (MySQL, PostgreSQL, MSSQL, Oracle, SQLite, generic SQLSTATE). - Boolean-based: Send
' OR '1'='1and' OR '1'='2. If response sizes differ significantly, the condition is being evaluated inside SQL. - Time-based blind: DB-specific sleep payloads (
SLEEP(),pg_sleep(),WAITFOR DELAY, SQLiterandomblob).
XSS with context awareness
A reflected marker is not proof of XSS — it's proof of reflection. The verifier sends five payloads targeting different contexts and checks whether the full payload (not just the marker) reflects unencoded:
HTML tag: <x-WISXSS123>
Attribute: "WISXSS123"
JS string: ';WISXSS123;'
Event handler: <img src=x onerror=WISXSS123()>
Script body: <script>WISXSS123</script>
If the payload reflects in a "dangerous" context (inside a tag attribute, event handler, or script), it's HIGH severity. If only the marker (not the payload) reflects, it's LOW — means output is being filtered but reflection exists, worth manual investigation.
What a Verify Now report contains
Every verification produces:
- Verdict: VULNERABLE / LIKELY_VULNERABLE / NOT_VULNERABLE / INCONCLUSIVE
- Confidence score: 0-100% based on how clean the evidence was
- Full request log: every HTTP request with URL, status, bytes, timing
- Evidence section: what triggered the verdict, colored by impact
- Attack walkthrough: recon → probe → confirm → weaponize → business impact
- Remediation code: copy-paste fixes in PHP, Python, Node.js + server config
Safe by design
Every payload is non-destructive. No DROP TABLE, no file writes, no network callouts. The command injection test uses only echo and sleep. The SQL test is all SELECT-based. The XSS test relies on static canary strings that wouldn't execute even if rendered — verification proves reflection/execution could happen, not that it has.
This matters because Verify Now can be triggered accidentally in the middle of a scan with client traffic on the site. Safe defaults mean you can click it without rehearsing.