agentsafe/webscan

Passive-first web security scanning

A web scanner that treats the page as untrusted input.

AgentSafe WebScan turns a public URL into a compact, evidence-based security report — through a CLI, SARIF 2.1.0 for code scanning, and MCP for coding agents. The scanner is deterministic, needs no LLM, and never forwards raw page content into a model's context.

agentwebscan https://example.com
AgentSafe WebScan 0.1.0 · passive
https://example.com/ · HTTP 200 · score 62/100 (D)

[MEDIUM] Content Security Policy is missing
  Content-Security-Policy header not present
  CWE-1021
  Fix: Deploy a restrictive CSP and iterate with report-only mode first.

[MEDIUM] Potential hidden instructions for AI agents
  2 hidden segment(s) matched: do not tell user, assistant role;
  content withheld, hashes: 59bc47934ec7ef56, d4f45e4dada56e42
  OWASP LLM01:2025

Passive mode is the default. No exploit payloads, no credential
attacks, no brute force, no port scans, no subdomain enumeration.

The different part: the scanner is an agent trust boundary

Once a scanner is exposed over MCP, website content can flow straight into a coding agent. That is an indirect prompt-injection path classic web scanners were never designed around. Two controls exist specifically for it.

Quarantined evidence

Suspicious text is fingerprinted, not quoted

Hidden instructions aimed at agents are classified and SHA-256 fingerprinted. The matched text itself never leaves the scanner. Potential .env and debug-log bodies are hashed in memory and omitted from findings entirely.

Structured findings

Bounded fields instead of a page dump

Agents receive severity, confidence, standard, evidence and remediation — plus read-only, idempotent and open-world tool annotations, so the agent knows what the call does before making it.

Honest coverage

"Could not check" is not "clean"

A probe that never reached the target is reported as incomplete, with the reason. A transient connection reset during a scan can't quietly turn a critical exposure check into a clean bill of health.

Safe fetch

SSRF guard with DNS pinning

Public HTTP(S) targets only. Private and reserved ranges are refused, validated DNS answers are pinned for the actual socket to close the rebinding gap, every redirect hop is re-validated, and one timeout budget covers the whole call.

What it looks at

Deliberately narrower than a pentest suite. Findings keep severity separate from confidence, so a heuristic signal is never presented as a confirmed vulnerability.

AreaExamples
HeadersHSTS, CSP strength, clickjacking protection, nosniff, Referrer-Policy, version disclosure
CookiesSecure, HttpOnly on session-like cookies, SameSite
CORSArbitrary origin reflection, credentialed reflection, misleading wildcards
FrontendMixed content, outdated jQuery, third-party scripts without SRI
Agent securityHidden and comment-based prompt-injection heuristics, Unicode obfuscation controls
Exposure (opt-in).git/HEAD, .env, phpinfo.php, Apache server-status, WordPress debug.log
Hygienesecurity.txt, lightweight technology fingerprinting
AI surfacellms.txt presence and MCP references found in the page

Not in scope, by design. No exploit chains, no credential attacks, no brute force, no port scanning, no subdomain enumeration. Exposure probes are a small fixed set of GET requests behind --authorized, for systems you own or are explicitly permitted to test.

Get started

Requires Node.js 22 or newer. No API key, no account, no remote service.

Clone and install

git clone https://github.com/keepiteinfach/agent-safe-webscan
cd agent-safe-webscan && npm install

Scan a site

npm run scan -- https://example.com

Wire it into CI

SARIF 2.1.0 goes straight into GitHub code scanning, and the exit code can gate a build.

npm run scan -- https://example.com --format sarif > report.sarif
npm run scan -- https://example.com --fail-on high

Use it from an agent

The MCP server exposes two tools over stdio: scan_site runs a bounded scan in passive or authorized mode, and scanner_policy returns the scanner's boundaries without touching the network — so an agent can check what it is about to invoke.

Register
codex mcp add agent-safe-webscan \
  -- node /abs/path/agent-safe-webscan/src/mcp.js
Then ask

“Scan https://example.com in passive mode and turn only the structured findings into a prioritized remediation plan.”

Why the policy tool exists. An agent deciding whether to call a scanner should be able to read the scanner's own limits first — default mode, what is never attempted, how untrusted evidence is handled — rather than inferring them from a description.

Project status

v0.1.0 · early

This is a young project and is presented as one. It has a full test suite, CI on Node 22 and 24 across Linux and Windows, a written threat model, and a stable report contract — but no adoption numbers to quote yet, and no npm release. The roadmap is in the repository; baseline diffing, a GitHub Action, and a streamable HTTP transport are next.

Rule contributions are welcome. New rules should be bounded, low-noise, carry a stable id, return no secrets, and ship with a regression test — see CONTRIBUTING.