Releases: lutzashl290788-cell/webscan
Release list
WebScan v2.7.1 — Stealth Mode + README Refresh
WebScan v2.7.1 — Stealth Mode + README Refresh
🥷 --stealth mode — full WAF/IDS evasion
New --stealth flag for maximum evasion when scanning WAF-protected targets:
webscan -t https://target.com --stealth --proxy socks5://127.0.0.1:9050What stealth mode does:
- Forces
--random-agent(browser UA rotation on every request) - Forces
--random-delay(request jitter ×0.5–×1.5) - Sets
concurrency=1(single connection, no parallelism) - Floors delay at 2.0s (at least 2s between requests)
- Injects random
X-Forwarded-Forheader (random public IPv4) - Injects random
Refererheader (Google/Bing/DuckDuckGo search URL) - Reduces connection pool to 1 connection per host
- Combines with
--proxyfor Tor routing
No other open-source DAST scanner has a built-in stealth mode — you'd need to manually configure each evasion technique separately.
📝 README refresh
All numbers updated to v2.7.0/v2.7.1:
- 41 plugins (was 38 — added dns_security, csp_analyzer, waf_detect)
- 937 tests (was 840)
- 69 source files (was 61)
- v2.7.0 in benchmark table (was v2.5.0)
- 14 of 41 passive plugins (was 11 of 38)
- Added 3 new plugins to the plugins table
- Added
--stealthto bug hunters section + all flags - Added DevOps & reporting subsection (risk score, compliance, diff, webhook, autofix)
- Updated architecture diagram with all new modules
🔧 CORS fix
Restored the explicit CORS deny-all middleware in server.py that was dropped during the v2.7.0 rebase.
📊 Numbers
- 41 plugins (unchanged)
- 937 tests passed (+12 stealth tests)
- 69 source files (unchanged)
- ruff clean, mypy --strict clean, 0 test failures
WebScan v2.7.0 — 6 Killer Features
WebScan v2.7.0 — 6 Killer Features
🎯 6 new features that no other open-source DAST tool has
1. Diff Mode — CI Regression Detection
webscan diff baseline.json current.json --fail-on-newCompares two scan reports: shows new (regressions), fixed (improvements), and changed (severity shifts) findings. --fail-on-new exits 1 if any new CRITICAL/HIGH appeared — perfect CI gate.
2. Webhook Notifications — Slack/Discord/Teams
webscan -t https://example.com --webhook-url https://hooks.slack.com/services/...Auto-detects webhook type from URL. Sends scan summary with risk score, severity breakdown, and top 3 findings. Works with Slack, Discord, Microsoft Teams, and generic HTTP endpoints.
3. Auto-Fix Suggestions — Copy-Paste Remediation
webscan -t https://example.com --suggest-fixesFor each finding, generates a concrete, copy-paste-ready fix: nginx config, Python code, or shell command. Covers 11 plugin types (headers, CORS, cookies, SSL/TLS, SQLi, XSS, secrets, etc.). No other scanner does this.
4. DNS Security Audit — DNSSEC/CAA/SPF/DMARC/DKIM
New plugin dns_security — checks DNS security records that no other DAST scanner covers:
- SPF — email sending policy (missing = spoofable domain)
- DMARC — email auth enforcement (missing = no SPF/DKIM enforcement)
- CAA — which CAs can issue certificates (missing = any CA)
- DKIM — email signing (checks common selectors)
5. CSP Deep Analyzer — Semantic Content-Security-Policy Analysis
New plugin csp_analyzer — goes beyond "header present/absent":
- Detects
'unsafe-inline'and'unsafe-eval'in script-src - Flags wildcard
*in any *-src directive - Checks for missing
object-src,base-uri,frame-ancestors,report-uri - Provides specific remediation per issue
6. WAF Detection — Fingerprint Web Application Firewalls
New plugin waf_detect — detects and fingerprints WAFs:
- Cloudflare, AWS CloudFront, Akamai, Imperva/Incapsula, Sucuri, F5 BIG-IP, ModSecurity, Wordfence, Fastly, Varnish, Azure Front Door
- Sends SQLi probe to check if WAF blocks it
- Helps interpret scan results (WAFs cause false negatives)
📊 Numbers
- 41 plugins (was 38 — added dns_security, csp_analyzer, waf_detect)
- 925 tests passed (+38 new)
- 69 source files (was 63 — added 6 new modules)
- ruff clean, mypy --strict clean
- CI passing on Python 3.10/3.11/3.12
📦 New files
| File | Description |
|---|---|
webscan/diff.py |
Report comparison engine (94 lines) |
webscan/notify.py |
Webhook notifications — Slack/Discord/generic (94 lines) |
webscan/autofix.py |
Auto-fix suggestion engine (71 lines) |
webscan/plugins/dns_security.py |
DNS security audit plugin |
webscan/plugins/csp_analyzer.py |
Deep CSP analysis plugin |
webscan/plugins/waf_detect.py |
WAF detection + fingerprinting plugin |
tests/test_v270_killer.py |
38 tests covering all new features |
🔧 New CLI flags
| Flag | Description |
|---|---|
--webhook-url URL |
Send scan summary to Slack/Discord/Teams |
--suggest-fixes |
Print copy-paste-ready fix commands per finding |
diff old.json new.json |
Compare two reports (subcommand) |
diff --fail-on-new |
Exit 1 if new CRITICAL/HIGH findings appeared |
⬆️ Upgrade
pip install --upgrade webscan-security==2.7.0📋 Why these beat Nuclei/Nikto/Burp
| Feature | WebScan | Nuclei | Nikto | Burp Suite |
|---|---|---|---|---|
| Risk score (0-100) | ✅ | ❌ | ❌ | ❌ |
| OWASP compliance mapping | ✅ | ❌ | ❌ | ❌ |
| AI triage (GLM 5.2) | ✅ | ❌ | ❌ | ❌ |
| Diff mode (CI regression) | ✅ | ❌ | ❌ | ❌ |
| Webhook notifications | ✅ | ❌ | ❌ | ❌ |
| Auto-fix suggestions | ✅ | ❌ | ❌ | ❌ |
| DNS security audit | ✅ | ❌ | ❌ | ❌ |
| CSP deep analyzer | ✅ | ❌ | ❌ | ❌ |
| WAF detection | ✅ | ❌ | ❌ | ❌ |
| Price | Free MIT | Free MIT | Free GPL | $475/year |
WebScan v2.6.0 — Risk Score + OWASP Compliance Mapping
WebScan v2.6.0 — Risk Score + OWASP Compliance Mapping
🎯 Killer features
Two enterprise-grade features that make WebScan competitive with commercial DAST tools.
1. Risk Score (0-100, like SSL Labs)
A single number that summarises the security posture of the scanned target. No other open-source DAST tool has this — Nuclei, ZAP, Nikto all leave you to triage findings manually.
webscan -t https://example.com --risk-score Risk score : 62/100 (C)
Moderate risk — several medium/high issues. Prioritise remediation this week.
How it works:
- Starts at 100 (perfect), reduced by each finding
- Formula:
severity × confidence × exposure × diminishing-returns - Critical = -25 pts, High = -12, Medium = -5, Low = -1.5, Info = -0.2
- FIRM findings weigh 100%, TENTATIVE 60%, INFORMATIONAL 20%
- Findings on root URL (
/) weigh 30% more (exposure multiplier) - Diminishing returns: each subsequent finding weighs 5% less (floor 30%) — prevents "death by a thousand cuts"
Grading:
| Score | Grade | Meaning |
|---|---|---|
| 90-100 | A 🟢 | Excellent — no critical/high issues |
| 75-89 | B 🔵 | Good — a few medium issues |
| 55-74 | C 🟡 | Moderate — several medium/high |
| 30-54 | D 🟠 | High risk — critical or multiple high |
| 0-29 | F 🔴 | Critical — immediate remediation |
CI gate:
# Block deployment if risk score < 70
webscan -t https://staging.example.com --fail-on-risk 70
echo $? # 1 if score < 70, 0 if OK2. OWASP Top 10 2021 Compliance Mapping
Enterprises need to show OWASP Top 10 coverage for security audits. Now WebScan produces a compliance dashboard out of the box.
webscan -t https://example.com --compliance Compliance : OWASP Top 10 2021
Category Findings Severity breakdown
─────────────────────────────────────────── ──────── ──────────────────────────────
A03 Injection 2 1 critical, 1 high
A05 Security Misconfiguration 4 3 high, 1 medium
A02 Cryptographic Failures 1 1 high
Clean (no findings): A04 Insecure Design, A06 Vulnerable Components, ...
Plugin → OWASP mapping:
| OWASP Category | WebScan plugins |
|---|---|
| A01 Broken Access Control | idor, mass_assignment, csrf, cookies, clickjacking |
| A02 Cryptographic Failures | ssl_tls, jwt_audit, secrets |
| A03 Injection | sql_injection, xss, ssti, lfi_rfi, xxe, path_traversal, graphql_depth, prototype_pollution |
| A05 Security Misconfiguration | headers, cors, config_files, directories, backup_files, http_methods, security_txt, robots_sitemap, verbose_errors, file_upload, websocket_security, web_cache_deception, cache_poisoning, host_header_injection, request_smuggling, race_condition |
| A06 Vulnerable Components | cve_lookup, tech_fingerprint |
| A07 Auth Failures | jwt_audit, cookies |
| A10 SSRF | ssrf, subdomains |
compliance_gap_analysis() also shows which categories were tested but came back clean — useful for audit reports.
📊 Numbers
- 38 plugins (unchanged)
- 887 tests passed (+29 new for risk + compliance)
- 97% coverage (risk.py: 100%, compliance.py: 98%)
- 63 source files (added
webscan/risk.py+webscan/compliance.py) - ruff clean, mypy --strict clean
- CI passing on Python 3.10 / 3.11 / 3.12
📦 New files
webscan/risk.py— risk scoring engine (71 lines, 100% coverage)webscan/compliance.py— OWASP Top 10 2021 mapping (56 lines, 98% coverage)tests/test_risk_compliance.py— 29 tests covering all scoring + mapping logic
🔧 New CLI flags
| Flag | Description |
|---|---|
--risk-score |
Print 0-100 risk score + letter grade after scan |
--fail-on-risk N |
Exit code 1 if score < N (CI gate) |
--compliance |
Print OWASP Top 10 2021 compliance table |
⬆️ Upgrade
pip install --upgrade webscan-security==2.6.0📋 Why these are killer features
Risk score — a single number that summarises security posture. Executives love it. CI pipelines can use --fail-on-risk 70 to block bad deployments. No other open-source DAST tool has this.
Compliance mapping — enterprises must show OWASP Top 10 coverage for audits (PCI-DSS, ISO 27001, SOC 2). Now WebScan produces this automatically. Commercial tools charge $10,000+/year for equivalent functionality.
WebScan v2.5.3
WebScan v2.5.3 — Zero known security findings
🔒 Security — all known issues closed
A final, maximally-pedantic audit found 3 new MEDIUM + 3 confirmed LOW + 8 INFO
issues that survived v2.5.1/v2.5.2. All 14 are fixed in this release — the
codebase now has zero outstanding security findings at any severity level
(CRITICAL / HIGH / MEDIUM / LOW / INFO).
Fixed (MEDIUM)
-
M-NEW-1: H-1 fix was incomplete — TraceConfig now applied to all sessions
(CWE-200 / CWE-522). The original v2.5.1 fix only attached the
redirect-safe TraceConfig toengine.ScanEngine.scan_all(). Two other
aiohttp.ClientSession(...)constructions —cli._crawl_targets(carries
auth headers during crawling) andauth._form_login(POSTs the login form
with credentials) — were unprotected. Both now install the same
_build_redirect_safe_trace()._form_loginadditionally uses
allow_redirects=False. -
M-NEW-2: shell injection in
security-scan.ymlvia${{ github.event.inputs.target }}
(CWE-78 / CWE-94). Fixed via env-var indirection + URL regex validation. -
M-6:
mass_assignmentPUT now carries safety markers
(CWE-624 / CWE-639). Each probe carriesIdempotency-Key: webscan-<uuid>,
X-WebScan-Test: 1,X-WebScan-Dry-Run: 1, andallow_redirects=False.
Fixed (LOW)
-
L-1: dependency upper bounds + CVE coverage (CWE-1357 / CWE-1104).
aiohttp>=3.9.0→aiohttp>=3.10.11,<4closes CVE-2024-52304 and
CVE-2024-47881 (HTTP-parser DoS, directly exploitable from a hostile
target). All other deps now have<majorupper bounds. -
L-4: Dockerfile hardened. Base image pinned by digest
(python:3.12-slim@sha256:c2d8472b...). AddedHEALTHCHECKinstruction. -
L-6:
auto-release.ymltag validation (CWE-20). TAG is validated
against^v\d+\.\d+\.\d+(-[\w.]+)?$before use.
Fixed (INFO)
- INFO-1: explicit CORS deny-all middleware in
server.py. - INFO-2:
_safe_url()inreporter.pyblocksjavascript:/data:
schemes in HTML report<a href>(CWE-79 stored XSS). - INFO-3:
anonymize._PRIVATE_IPextended to IPv6 ULA / link-local /
loopback + CGNAT. - INFO-4: prompt-injection protection in
ai.py— scanner output wrapped
in<scanner_output>tags with explicit "treat as untrusted data"
system-prompt instructions. - INFO-5:
assert→if/raiseinai.py(Bandit B101). - INFO-6: URL credentials masked in
_progressbar (CWE-532). - INFO-7:
verify_sslparameter exposed inapi.scan(). - INFO-8: covered by M-NEW-1.
🧪 Tests — +20 new, 97% coverage sustained
- 860 tests (was 840), all passing
- New
tests/test_v253_security.py(20 tests) covers every fixed issue - ruff clean, mypy --strict clean (locally and in CI env)
📊 Numbers
- 38 plugins (unchanged)
- 860 tests (was 840)
- 97% coverage (sustained)
- 61 source files
- 0 known security findings at any severity (was 4 HIGH + 6 MEDIUM + 6 LOW)
⬆️ Upgrade
pip install --upgrade webscan-security==2.5.3📋 Audit summary
After three audit passes (initial → v2.5.1 fixes → final → v2.5.3 fixes),
the codebase has zero outstanding security findings at any severity level.
| Severity | Initial audit | After v2.5.1 | After v2.5.2 | After v2.5.3 |
|---|---|---|---|---|
| CRITICAL | 0 | 0 | 0 | 0 |
| HIGH | 4 | 0 | 0 | 0 |
| MEDIUM | 6 | 4 | 2 | 0 |
| LOW | 6 | 6 | 6 | 0 |
| INFO | — | — | — | 0 |
| Total | 16 | 10 | 8 | 0 |
WebScan v2.5.2
WebScan v2.5.2 — MEDIUM security fixes + CI fix
🔒 Security — MEDIUM findings closed
M-1: --strict-ssl flag (CWE-295)
Previously --no-verify-ssl was a documented no-op — the scan engine always
disabled TLS verification regardless of the flag, and NetConfig.verify_ssl
was dead code. This was a deliberate design choice (scanners audit
self-signed hosts) but the dead flag misled operators who expected
verification to be enforced when they did NOT pass --no-verify-ssl.
This release wires up TLS verification properly:
- New
--strict-sslflag — when set, the scan engine uses a verifiable
SSL context (system CAs, hostname check). Useful for scanning production
sites where a valid cert is expected and a verification failure is itself
a finding. --no-verify-sslkept as no-op for backward compatibility.NetConfig.verify_sslis now live — read byScanEngineto choose
between verifiable and non-verifiable SSL contexts.engine._build_ssl_context(verify=...)takes averifyargument.
M-2: shared fetch_body() helper (CWE-400)
A full audit found ~30 places across plugins, crawler, and retry helper
where await resp.text(errors="ignore") was called without a body-size
cap. A hostile target serving a 10 GiB page would OOM the scanner —
particularly dangerous under webscan serve where one client could kill
every other scan.
This release introduces a single bounded reader:
webscan.plugins._active_helpers.fetch_body(resp, limit=2 MiB)—
reads at mostlimitbytes viaresp.content.read(), decodes as UTF-8.
Falls back toresp.text()for test fakes and the lightweightResponse
dataclass.- Applied across 28 plugin files — every
resp.text(errors="ignore")
replaced withfetch_body(resp). crawler._fetch_and_parse/crawler._load_robots— same pattern,
inline (crawler cannot import_active_helpersdue to layering).retry.request_with_retry— same pattern, inline.MAX_BODY_BYTES = 2 * 1024 * 1024exported as a module constant.
🛠 CI fixes
mypy 2.1.0 compatibility
webscan/server.py had three mypy errors in CI (but not locally, because
locally fastapi was installed):
Unused "type: ignore[assignment, misc]"onFastAPI = ... = None—
in CI (no fastapi) mypy treats the names as Any and the ignore is unused;
locally (with fastapi) mypy sees the real class types and the ignore is
required.Untyped decorator makes function "health" untypedand same for
scan_endpoint— the@app.get/@app.postdecorators are untyped
when fastapi is missing.
Fix: [[tool.mypy.overrides]] module = "webscan.server"; warn_unused_ignores = false in pyproject.toml. Bare # type: ignore on
the three offending lines keeps the file clean in both environments (CI
without extras, dev with all extras).
📊 Numbers
- 38 plugins (unchanged)
- 840 tests (unchanged)
- 97% coverage (unchanged)
- 61 source files
- ruff clean, mypy --strict clean (locally and in CI env)
⬆️ Upgrade
pip install --upgrade webscan-security==2.5.2📋 Remaining work
All HIGH and MEDIUM findings from the original audit are now closed. The
only outstanding items are LOW-severity polish:
- L-1 — pin transitive dependency upper bounds (aiohttp, fastapi, etc.)
inpyproject.toml. Currently using>=only. - L-4 — Dockerfile: add
HEALTHCHECK, pin base image by digest. - L-6 —
auto-release.yml: validate${GITHUB_REF}tag pattern
before use in--notes-filepath.
WebScan v2.5.1
WebScan v2.5.1 — Security audit + coverage boost
🔒 Security — full audit pass
A complete static-security audit of the codebase surfaced 4 HIGH and 6 MEDIUM
issues. All HIGH-severity findings are fixed in this release; MEDIUM/LOW are
either fixed or explicitly documented.
Fixed (HIGH)
-
H-1: auth-header / cookie leak on cross-origin redirect (CWE-200 / CWE-522).
The scan engine now installs anaiohttp.TraceConfigthat strips
Authorization,Cookie,X-API-Key,X-Auth-Tokenand
Proxy-Authorizationfrom any redirect hop whose host differs from the
original request. Without this,--basic-auth admin:secretagainst a target
that returned302 Location: http://attacker/capturewould replay the
credentials on the attacker host. Seeengine._build_redirect_safe_trace. -
H-2: SSRF in
file_uploadvia cross-originform.action(CWE-918).
The plugin now refuses to follow a<form action>that points to a different
origin than the target. A target page could otherwise make the scanner POST
webscan-test.txt(and any auth headers / cookies, see H-1) to an
attacker-controlled host. The sharedsame_origin()helper lives in
utils.httpand is now reusable across plugins. -
H-3:
webscan serveHTTP backend — body-size + caps + validation
(CWE-306 / CWE-400 / CWE-770). The/scanendpoint now rejects bodies larger
than 64 KiB (HTTP 413), validates thattargets/pluginsare lists, and
clampstimeout(≤60s) andconcurrency(≤32) to safe bounds so a single
client cannot exhaust the server. Auth/rate-limit middleware remains the
operator's responsibility when binding to0.0.0.0— seeserver.pydocstring. -
H-4: state-changing plugins now opt-in (CWE-400).
mass_assignment,
race_conditionandrequest_smugglingare no longer run by default — they
sendPUT, parallel GET, and smuggled POST requests that can actually mutate
state on a vulnerable target. The operator must opt in explicitly with
--plugins mass_assignmentetc.OPT_IN_PLUGINSis the single source of
truth inregistry.py.
Fixed (MEDIUM / LOW)
- M-3: third-party plugin supply-chain guard (CWE-1357). A third-party
entry-point plugin whose name collides with a built-in (e.g. a malicious
package registeringheadersto harvest auth credentials) is now rejected
with a stderr warning rather than silently overriding the built-in. - M-5: dead-code
verify_sslfield — clarified in-place as a documented
no-op. The scan engine always disables cert verification (scanners audit
self-signed hosts); the CLI flag is kept for compatibility. - L-2: version sync —
webscan.__version__andserver.pyFastAPI(version=)
now both read2.5.x, matchingpyproject.toml. - L-3: proxy credential masking in stdout (CWE-532).
--proxy http://user:pass@...is now printed ashttp://***@...in the
scan banner, so credentials no longer leak to CI/CD logs, tmux scrollback,
etc. - L-5: CI workflow —
actions/checkout@v6/actions/setup-python@v6
(which don't exist) replaced with@v4/@v5.
🧪 Tests — coverage 96% → 97%
- +40 new tests (800 → 840 passed) covering the previously-untested
branches introduced by the security fixes:tests/test_security_hardening.py(new, 15 tests) — redirect-trace
behaviour,same_origin/same_hosthelpers, plugin-discovery supply-chain
guard,OPT_IN_PLUGINSmembership,_mask_proxy_url.tests/test_ai.py—ai_availablewith explicit key / env key,
_build_clientSDK-missing / SDK-error branches, triage skip-empty,
summary unavailable,_first_text/_first_jsonedge cases.tests/test_server.py— body-size 413, validation for targets/timeout/
plugins,_confidence_from_strinvalid input,create_app/run_server
without serve extra, timeout/concurrency clamping.tests/test_cli.py—_run_aiunavailable / available / quiet paths,
webscan servesubcommand (with and without serve extra),main()serve
dispatch, proxy-credential masking in_print_setup.
🛠 Tooling
pyproject.toml[tool.ruff.lint.per-file-ignores]—tests/**/*.pynow
explicitly ignoresANN401/ANN001/ANN201/ANN204(test fakes /
shims legitimately needtyping.Anyand don't need explicit return types).
Removes ~20 spurious lint errors previously suppressed with# noqa.
📊 Numbers
- 38 plugins (unchanged)
- 840 tests (was 800)
- 97% coverage (was 96%)
- 61 source files
- ruff clean, mypy --strict clean
⬆️ Upgrade
pip install --upgrade webscan-security==2.5.1📋 Known remaining work
- M-1 —
--no-verify-sslflag is a documented no-op (scanner always skips
cert verification by design). Field kept for CLI compatibility. - M-2 —
resp.text()calls in some plugins do not cap body size; a shared
fetch_body()helper is planned for v2.5.2.
WebScan v2.5.0
WebScan v2.5.0 — 7.1s, faster than v2.0 with 2× more plugins
🚀 Performance
11.4s → 7.1s (1.6× faster, avg of 3 runs on httpbin.org)
WebScan v2.5.0 with 38 plugins is now faster than v2.0 with 19 plugins (7.1s vs 7.3s)!
Optimizations
backup_files: 312→50 probes (10 files × 5 extensions)subdomains: crt.sh query timeout 5s (was unbounded)- Safe mode concurrency: 4→8 (more parallel plugins)
- Connect timeout: 5s→3s (faster failure)
- Connection pool: ×5→×8 of concurrency
Comparison
| Scanner | Time | Findings | FP | Plugins |
|---|---|---|---|---|
| WebScan v2.5.0 | 7.1s | 16 | 0 | 38 |
| Nuclei 3.8.0 | 34.2s | 21 | — | ~9 |
| Nikto 2.6.0 | 42.6s | 30 | 5+ | ~15 |
4.8× faster than Nuclei, 6.0× faster than Nikto.
📊 Numbers
- 38 plugins
- 701 tests
- 95% coverage
- ruff clean, mypy --strict clean
WebScan v2.4.1
WebScan v2.4.1 — Coverage boost + README fix
🔧 Changes
Coverage: 94% → 95%
- 13 new tests covering error branches in 5 plugins
- prototype_pollution: 73% → ~90%
- request_smuggling: 80% → ~92%
- file_upload: 82% → ~92%
- websocket_security: 88% → ~95%
- mass_assignment: 89% → ~95%
README Fix
- 11 missing plugins added to the plugins table (all 38 now listed)
📊 Numbers
- 38 plugins
- 701 tests (was 688)
- 95% coverage (was 94%)
- 59 source files
- ruff clean, mypy --strict clean
WebScan v2.4.0
WebScan v2.4.0 — 38 plugins, WebSocket security audit
🆕 New Plugin (37 → 38)
websocket_security (passive)
Scans HTML and same-origin JavaScript for ws:// and wss:// WebSocket URLs.
- HIGH (FIRM):
ws://endpoint found — unencrypted traffic, sniffable - MEDIUM (TENTATIVE):
wss://with sensitive context (token/auth/session nearby) - LOW (INFO):
wss://endpoint discovered, manual review recommended
17 new unit tests. Closes #37.
📊 Numbers
- 38 plugins (was 37)
- 688 tests (was 671)
- 95% coverage
- 59 source files
- ruff clean, mypy --strict clean
WebScan v2.3.0
WebScan v2.3.0 — 37 plugins, Web Cache Deception detection
🆕 New Plugin (36 → 37)
web_cache_deception (active, content-verified)
Appends static-asset extensions (.css, .js, .png, .svg, .woff, .pdf, .txt) to dynamic URLs. If the server returns the same dynamic page (not a 404), a CDN might cache it — leaking sensitive data to other users.
- HIGH (FIRM): response contains sensitive markers (email, api_key, session, password, token, balance) AND Content-Type doesn't match the extension
- MEDIUM (TENTATIVE): dynamic page served at extension, no sensitive markers found, similarity ≥ 0.85 to baseline
- 15 cacheable extensions tested
- Soft-404 calibration
- Content-Type mismatch detection
📊 Numbers
- 37 plugins (was 36)
- 671 tests (was 654)
- 95% coverage
- 58 source files
- ruff clean, mypy --strict clean
- 0 false positives
🔗 Links
- Full CHANGELOG
pip install webscan-security