Reconnaissance and Enumeration for Agent Protocols · v0.1.1 · MIT · Go
REAP
Black-box reconnaissance for AI agent endpoints. Point it at an MCP endpoint you’re authorised to test: it confirms the protocol, lists what an anonymous caller can reach, and reports auth and transport posture, without invoking anything it finds.
brew install hackwither/tap/reap reap -t https://your-host/mcp --authorized
GitHub·release v0.1.1·all install options·19 rules·practice range·docs
Why it exists
The MCP gateway your team shipped last sprint. The agent endpoint a bug bounty programme just put in scope. REAP is external, unauthenticated, black-box recon against a live agent endpoint, from the position an actual attacker occupies.
MCP today. A2A and OpenAPI are identified, with full transport posture
Tools like mcprobe inspect the MCP server you’re about to install. REAP inspects the endpoint you’ve already exposed, from outside, with no credentials and no invocation. Different lane, no check overlap.
It reads, never invokes
The safety boundary is enforced by the type system, not by review. A probe is handed a Session, and that is its entire surface:
type Session interface {
TargetURL() string
Do(ctx context.Context, method string, params any, opts ...ReqOption) (*RawResult, error)
}No Call. No Invoke. No method on Session can dispatch a discovered tool. JSON templates are deliberately not Turing-complete: one request, a fixed set of matchers. If you find a way for a probe or template to do more than read-only enumeration, that’s a bug: report it.
tools/call, the MCP method that executes a tool, is kept out by a test, not by convention.A real report
What the endpoint is comes first, then posture findings, each with a stable rule ID, confidence, evidence, an OWASP Agentic Top 10 reference and a fix. This is an unedited scan of the deliberately insecure reap-range target:
reap 0.1.2-dev+ad8ce39 · reap-range, bad target
reap -t http://localhost:8080/mcp --authorized
REAP / AI AGENT RECON ──────────────────────────────────────────────────────────────────── v0.1.2-dev+ad8ce39 TARGET http://localhost:8080/mcp ::1 • MCP 2025-06-18 • http-streamable • CONFIRMED Agent reap-range 0.1.0 Edge Werkzeug/3.0 Python/3.12.3 Discovery mcp-http-streamable • high confidence Auth open • enumeration answered without credentials Surface 3 tools • 1 resources • 1 prompts FINDINGS 15 matched • use -v for full evidence HIGH mcp-unauth-tools-list HIGH CONFIDENCE MCP tool listing accessible without authentication tools/list returned 3 tool(s) to an unauthenticated caller: exec_shell, search_tools, run_tool Evidence POST http://localhost:8080/mcp → 200 • application/json • 783 B OWASP ASI02: Tool Misuse and Exploitation, ASI03: Identity and Privilege Abuse Fix Require authentication before tools/list, or scope the response so anonymous callers see nothing. HIGH mcp-host-header-validation HIGH CONFIDENCE MCP accepted initialize with a mismatched Host header The server processed an initialize request even though the Host header was set to "host-header-validation.invalid", so it does not validate the requested host name before handling MCP traffic. This is the condition DNS-rebinding protection prevents; it is rated high only for loopback endpoints, where a browser-driven rebinding attack reaches a local agent directly. Evidence POST http://localhost:8080/mcp → 200 • application/json • 329 B OWASP ASI03: Identity and Privilege Abuse Fix Validate the Host header or equivalent request target before accepting MCP requests, and refuse requests whose host name does not match the configured endpoint. HIGH mcp-dynamic-dispatch MEDIUM CONFIDENCE Enumerated MCP tool surface is likely incomplete (dynamic dispatch detected) Discovery tool(s) search_tools and executor tool(s) run_tool were detected. This indicates tools/list likely undercounts the real capability surface because callable tools can be reached through search + dispatch. Evidence POST http://localhost:8080/mcp → 200 • application/json • 783 B OWASP ASI09: Human-Agent Trust Exploitation Fix Expose a complete dispatchable tool manifest or provide a discoverable read-only tool inventory (for example, an extended list endpoint) so downstream security tooling can account for the full surface. HIGH http-cors-wildcard Permissive CORS policy on agent endpoint Server returns Access-Control-Allow-Origin: * — any web origin can call this endpoint from a browser context. Combined with Access-Control-Allow-Credentials: true, this allows credentialed cross-origin requests, which browsers should normally block. OWASP ASI03: Identity and Privilege Abuse Fix Scope Access-Control-Allow-Origin to known first-party origins; never reflect an arbitrary Origin, and never combine * with credentialed requests. MED mcp-redirect-uri-laxity MEDIUM CONFIDENCE OAuth redirect URI registration appears overly broad The discovered OAuth metadata includes redirect URIs that are broad or wildcarded, which increases the risk of confused-deputy or open redirect abuse. Evidence GET http://localhost:8080/.well-known/oauth-authorization-server → 200 OWASP ASI03: Identity and Privilege Abuse Fix Restrict registered redirect URIs to exact allowed origins and paths, and avoid wildcards or overly permissive URL patterns. MED mcp-session-id-entropy HIGH CONFIDENCE MCP session ID entropy looks weak or predictable The MCP session ID returned by the server appears to have low entropy or a predictable format: session ID is shorter than 16 characters, estimated entropy is low (36 bits) OWASP ASI03: Identity and Privilege Abuse Fix Use a cryptographically random, high-entropy session identifier for MCP sessions and avoid sequential or human-readable formats. MED transport-plaintext Agent endpoint served over plaintext HTTP Target URL uses http:// rather than https://. Tool calls, arguments, and any auth tokens are visible to on-path observers. OWASP ASI07: Insecure Inter-Agent Communication Fix Serve agent endpoints over TLS only; redirect or refuse plaintext connections. MED mcp-tmpl-high-risk-tool-names HIGH CONFIDENCE Tool list includes names suggesting code execution or filesystem access The tool list (requested with credentials, if any were supplied) includes a tool name matching patterns associated with code-execution or raw-filesystem primitives. This is a triage signal for closer review; verify the tool's actual capabilities and authorization model. Evidence POST http://localhost:8080/mcp → 200 • application/json • 783 B OWASP ASI02: Tool Misuse and Exploitation, ASI05: Unexpected Code Execution (RCE) Fix Review tool capabilities in context. If the tool performs code execution or unrestricted filesystem access, scope it behind explicit, auditable authorization separate from general tool listing. Consider narrower alternatives. LOW mcp-oauth-metadata-posture HIGH CONFIDENCE Published OAuth metadata does not advertise PKCE OAuth metadata was published at /.well-known/oauth-authorization-server, but it does not advertise PKCE (code_challenge_methods_supported) support. Evidence GET http://localhost:8080/.well-known/oauth-authorization-server → 200 • application/json OWASP ASI03: Identity and Privilege Abuse Fix Advertise PKCE support (code_challenge_methods_supported: ["S256"]) in published OAuth authorization-server metadata. LOW mcp-instructions-exposure MEDIUM CONFIDENCE MCP handshake returns lengthy or sensitive-flavored instructions The initialize response's 'instructions' field is long and/or contains language patterns (secrecy directives, 'internal', credential-related terms) worth a human review to confirm it isn't leaking operational or internal detail to any caller. Evidence POST http://localhost:8080/mcp → 200 • application/json • 329 B OWASP ASI09: Human-Agent Trust Exploitation Fix Keep client-facing instructions limited to usage guidance; keep anything sensitive out of fields returned pre-authentication. LOW mcp-resources-prompts-exposure-resources-list HIGH CONFIDENCE Unauthenticated resources/list returns 1 item(s) resources/list succeeded without credentials and returned 1 item(s) to an anonymous caller. Evidence POST http://localhost:8080/mcp → 200 • application/json • 101 B OWASP ASI02: Tool Misuse and Exploitation Fix Gate resource/prompt listings behind authentication if their contents aren't meant to be public. LOW mcp-resources-prompts-exposure-prompts-list HIGH CONFIDENCE Unauthenticated prompts/list returns 1 item(s) prompts/list succeeded without credentials and returned 1 item(s) to an anonymous caller. Evidence POST http://localhost:8080/mcp → 200 • application/json • 117 B OWASP ASI02: Tool Misuse and Exploitation Fix Gate resource/prompt listings behind authentication if their contents aren't meant to be public. LOW http-rate-limit-absence No standard rate-limit headers observed The endpoint answered requests but sent no standard rate-limit response headers. This is a reconnaissance signal that the service may not be advertising rate limiting to clients; it is not proof that no limiting exists. OWASP ASI08: Cascading Failures Fix Expose standard rate-limit headers such as Retry-After, RateLimit-Remaining, and RateLimit-Limit, or document the expected client behavior when limits are reached. INFO mcp-tool-capability-surface HIGH CONFIDENCE Tool capability inventory (3 tools) Full tool surface exposed by this endpoint, for asset-inventory and diffing purposes. Evidence POST http://localhost:8080/mcp → 200 • application/json • 783 B OWASP ASI09: Human-Agent Trust Exploitation INFO mcp-tmpl-server-header-fingerprint MEDIUM CONFIDENCE Server response header discloses backend/edge software The response includes a Server or X-Powered-By header identifying backend software that appears to be the origin application, not a CDN/edge layer (which is already surfaced separately in the target fingerprint's Edge line). Not a vulnerability by itself, but useful fingerprinting context worth trimming in production. Evidence POST http://localhost:8080/mcp → 200 • application/json • 783 B OWASP ASI09: Human-Agent Trust Exploitation Fix Suppress or genericize identifying response headers in production deployments where they name the origin application. POSTURE HIGH RISK 17 checks • 14 matched • 1 clean • 2 skipped • 28ms 4 high · 4 med · 5 low · 2 info · 0 error
Silence means something
Most scanners tell you what they found. REAP also tells you what it could not check. Every probe returns one of three things: a finding, a reasoned “not applicable”, or a real error. It never swallows a failure as “nothing to report”, so the coverage line can only count what was actually tested:
17 checks • 14 matched • 1 clean • 2 skipped
If any check could not run, the scan is marked incomplete and the report leads with ⚠ SCAN INCOMPLETE — ABSENT FINDINGS ARE NOT CLEAN RESULTS. An endpoint that correctly requires credentials is a passing recon result (auth-gated), not a tool failure:
a target REAP couldn’t reach never renders as a clean one
reap -t http://localhost:8090/mcp --authorized --exclude transport-plaintext
REAP / AI AGENT RECON ──────────────────────────────────────────────────────────────────── v0.1.2-dev+ad8ce39 TARGET http://localhost:8090/mcp ::1 • MCP 2025-06-18 • http-streamable • CONFIRMED Agent reap-range 0.1.0 Discovery mcp-http-streamable • high confidence Auth auth-gated • live, but requires credentials to enumerate FINDINGS 1 matched • use -v for full evidence INFO mcp-enumeration-blocked HIGH CONFIDENCE Tool enumeration blocked by authentication tools/list returned 401 without credentials — the server correctly gates enumeration behind authentication, so no tool inventory is available from this vantage point. Evidence POST http://localhost:8090/mcp → 401 • application/json • 92 B OWASP ASI09: Human-Agent Trust Exploitation POSTURE INFORMATIONAL 16 checks • 1 matched • 13 clean • 2 skipped • 14ms 0 high · 0 med · 0 low · 1 info · 0 error
What it checks
Recon: capability surface
| mcp-auth-posture | MCP enumeration auth posture: open, auth-gated or unreachable | — |
| mcp-tool-capability-surface | Tool capability inventory (3 tools) | ASI09 |
| mcp-enumeration-blocked | Tool enumeration blocked by authentication | ASI09 |
| mcp-unauth-tools-list | MCP tool listing accessible without authentication | ASI02 ASI03 |
| mcp-resources-prompts-exposure | Unauthenticated resources/list returns 1 item(s) | ASI02 |
| mcp-dynamic-dispatch | Enumerated MCP tool surface is likely incomplete (dynamic dispatch detected) | ASI09 |
| mcp-instructions-exposure | MCP handshake returns lengthy or sensitive-flavored instructions | ASI09 |
Auth and session posture
| mcp-oauth-metadata-posture | Published OAuth metadata does not advertise PKCE | ASI03 |
| mcp-oauth-bearer-challenge-missing | Protected resource does not send a Bearer WWW-Authenticate challenge | ASI03 |
| mcp-redirect-uri-laxity | OAuth redirect URI registration appears overly broad | ASI03 |
| mcp-session-id-entropy | MCP session ID entropy looks weak or predictable | ASI03 |
| mcp-host-header-validation | MCP accepted initialize with a mismatched Host header | ASI03 |
Transport posture
| transport-plaintext | Agent endpoint served over plaintext HTTP | ASI07 |
| transport-downgrade | Plaintext agent listener alongside TLS on the same host | ASI07 |
| tls-cert-health | TLS certificate, protocol and cipher health on agent endpoints | ASI09 |
| http-cors-wildcard | Permissive CORS policy on agent endpoint | ASI03 |
| http-rate-limit-absence | No standard rate-limit headers observed | ASI08 |
Templates
| mcp-tmpl-high-risk-tool-names | Tool list includes names suggesting code execution or filesystem access | ASI02 ASI05 |
| mcp-tmpl-server-header-fingerprint | Server response header discloses backend/edge software | ASI09 |
Every rule ID is frozen once shipped, so /reap/rules/<id>/ is a permanent link you can cite in a report. reap --list-probes prints the live set.
Install
Homebrew
brew install hackwither/tap/reap
Docker
docker run --rm ghcr.io/hackwither/reap -t https://your-host/mcp --authorized
Linux and macOS binary
curl -sSL https://github.com/hackwither/reap/releases/download/v0.1.1/reap_0.1.1_linux_amd64.tar.gz | tar xz
Swap linux_amd64 for linux_arm64, darwin_amd64 or darwin_arm64. macOS binaries are unsigned: if ./reap refuses to run, xattr -d com.apple.quarantine ./reap.
Windows
curl -sSLo reap.zip https://github.com/hackwither/reap/releases/download/v0.1.1/reap_0.1.1_windows_amd64.zip && unzip reap.zip
Go
go install github.com/hackwither/reap/cmd/reap@latest
Single static binary. Zero third-party dependencies, no API key, no telemetry. Go 1.22+ to build from source.
Use it
Scan one endpoint
reap -t https://your-host/mcp --authorized
Find the endpoint on a bare host:port
reap -t 10.0.0.7:8080 --mode discover
See what an authenticated caller gets
reap -t https://your-host/mcp --auth-header "Bearer $TOKEN" --authorized
A whole scope list, as NDJSON
cat scope.txt | reap --authorized --output json --concurrency 10
Through Burp, for manual follow-up
reap -t https://your-host/mcp --authorized --proxy http://127.0.0.1:8080
In CI: SARIF to GitHub code scanning, fail on high
reap -t "$MCP_ENDPOINT" --authorized --output sarif --out reap.sarif --fail-on high
# .github/workflows/agent-recon.yml
- name: Upload REAP findings
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: reap.sarif| exit | meaning |
|---|---|
| 0 | Scan ran; nothing at or above --fail-on |
| 1 | Findings at or above --fail-on |
| 2 | Usage or validation error |
| 3 | Scan could not complete: findings are not a negative result |
Protocol support
| protocol | discovery | enumeration | transport posture |
|---|---|---|---|
| MCP (streamable HTTP) | yes | yes | yes |
| MCP (legacy HTTP+SSE) | yes | — | yes |
| MCP (WebSocket, non-standard) | yes | — | yes |
| A2A (agent card) | yes | — | yes |
| OpenAPI / REST tool surface | yes | — | yes |
Negotiates MCP 2025-06-18, 2025-03-26 and 2024-11-05, sends the spec-required notifications/initialized, and carries MCP-Protocol-Version on post-handshake requests.
Authorised use only
REAP sends real requests to real endpoints. Use it only against systems you own or are explicitly authorised to test, and respect bug bounty scope exactly. --authorized is an acknowledgement, not an access control. Unauthorised access is illegal in most jurisdictions even when every request is read-only.
Contribute and cite
Write your own checks as JSON templates, no Go required (guide). The one non-negotiable: nothing merged into REAP invokes a discovered capability. Issues and PRs on GitHub.
@software{kaur2026reap,
title = {REAP: Reconnaissance and Enumeration for Agent Protocols},
author = {Kaur, Bandana},
year = {2026},
version = {0.1.1},
license = {MIT},
url = {https://hackwither.co.in/reap/}
}