hackwither_

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

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.

What REAP sends: initialize, notifications/initialized, tools/list, resources/list, prompts/list, well-known discovery and OAuth metadata GETs, and a CORS preflight. What it never sends: tools/call. sends · read-only initialize notifications/initialized tools/list resources/list prompts/list GET /.well-known/* discovery mcp, agent card, openapi, oauth OPTIONS (CORS preflight) never sends tools/call in no shipped probe, template or fingerprint. a test scans the source and fails the build if one appears.
Fig. 2 Everything REAP puts on the wire is enumeration or metadata. tools/call, the MCP method that executes a tool, is kept out by a test, not by convention.

architecture and safety boundary

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

Checks per reap-range target: bad 14 matched, 1 clean, 2 skipped; gated 6 matched, 8 clean, 3 skipped; good 1 matched, 13 clean, 2 skipped matched ran clean skipped bad 14/1/2 gated 6/8/3 good 1/13/2
Fig. 1 Every check on the three reap-range targets, one square each. Pink: matched. Solid: ran and found nothing. Outlined: skipped because it didn’t apply. A skipped check is never counted as clean.
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

REAP rules per OWASP Agentic Top 10 category: ASI01 0, ASI02 3, ASI03 7, ASI04 0, ASI05 1, ASI06 0, ASI07 2, ASI08 1, ASI09 6, ASI10 0 01 ·mcp-unauth-tools-listmcp-resources-prompts-exposuremcp-tmpl-high-risk-tool-names 02 3mcp-unauth-tools-listmcp-oauth-metadata-posturemcp-oauth-bearer-challenge-missingmcp-redirect-uri-laxitymcp-session-id-entropymcp-host-header-validationhttp-cors-wildcard 03 7 04 ·mcp-tmpl-high-risk-tool-names 05 1 06 ·transport-plaintexttransport-downgrade 07 2http-rate-limit-absence 08 1mcp-tool-capability-surfacemcp-enumeration-blockedmcp-dynamic-dispatchmcp-instructions-exposuretls-cert-healthmcp-tmpl-server-header-fingerprint 09 6 10 ·
Fig. 3 Rules citing each OWASP Agentic Top 10 category, one square per rule. Pink: ASI03, identity and privilege abuse. Categories at zero describe runtime behaviour, such as goal hijack or memory poisoning, that recon without invocation can’t observe.

Recon: capability surface

mcp-auth-postureMCP enumeration auth posture: open, auth-gated or unreachable—
mcp-tool-capability-surfaceTool capability inventory (3 tools)ASI09
mcp-enumeration-blockedTool enumeration blocked by authenticationASI09
mcp-unauth-tools-listMCP tool listing accessible without authenticationASI02 ASI03
mcp-resources-prompts-exposureUnauthenticated resources/list returns 1 item(s)ASI02
mcp-dynamic-dispatchEnumerated MCP tool surface is likely incomplete (dynamic dispatch detected)ASI09
mcp-instructions-exposureMCP handshake returns lengthy or sensitive-flavored instructionsASI09

Auth and session posture

mcp-oauth-metadata-posturePublished OAuth metadata does not advertise PKCEASI03
mcp-oauth-bearer-challenge-missingProtected resource does not send a Bearer WWW-Authenticate challengeASI03
mcp-redirect-uri-laxityOAuth redirect URI registration appears overly broadASI03
mcp-session-id-entropyMCP session ID entropy looks weak or predictableASI03
mcp-host-header-validationMCP accepted initialize with a mismatched Host headerASI03

Transport posture

transport-plaintextAgent endpoint served over plaintext HTTPASI07
transport-downgradePlaintext agent listener alongside TLS on the same hostASI07
tls-cert-healthTLS certificate, protocol and cipher health on agent endpointsASI09
http-cors-wildcardPermissive CORS policy on agent endpointASI03
http-rate-limit-absenceNo standard rate-limit headers observedASI08

Templates

mcp-tmpl-high-risk-tool-namesTool list includes names suggesting code execution or filesystem accessASI02 ASI05
mcp-tmpl-server-header-fingerprintServer response header discloses backend/edge softwareASI09

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
exitmeaning
0Scan ran; nothing at or above --fail-on
1Findings at or above --fail-on
2Usage or validation error
3Scan could not complete: findings are not a negative result

Protocol support

protocoldiscoveryenumerationtransport posture
MCP (streamable HTTP)yesyesyes
MCP (legacy HTTP+SSE)yes—yes
MCP (WebSocket, non-standard)yes—yes
A2A (agent card)yes—yes
OpenAPI / REST tool surfaceyes—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.

responsible use and reporting

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/}
}