AIMap: nmap for the Agentic Era
AIMap turns “the exposed AI service surface” into a map you can query, score and verify. 32 Shodan queries find MCP servers, Ollama and vLLM endpoints sitting on the open internet; Nuclei templates identify the protocol and enumerate tools and system prompts; a 0–10 risk score ranks them by exposure; and protocol-specific engines verify the damage. The scanning engine is fully deterministic — the advertised “AI-powered attack analysis” is currently a config stub with no code behind it.
1. The problem it solves
The exposed-AI-service surface has grown fast over the past year: MCP servers, Ollama and vLLM instances that were meant for an internal network get mapped straight onto the public internet, many with no authentication by default. To an attacker, these are open APIs with tool calling built in. To a defender, they are attack surface nobody can see.
The catch is that conventional mapping tools don’t speak these protocols:
| Tool | How it finds things | Understands AI protocols | Enumerates exposed capabilities | Verifies impact |
|---|---|---|---|---|
| Raw Shodan | Keywords, ports | Partially, by guessing from banners | No | No |
| General-purpose scanners | Known targets + CVE templates | No | No | Template-driven |
| AIMap | 32 purpose-built queries | 11 protocol families | Tools / models / system prompts | Scripted per protocol |
AIMap’s official tagline is “nmap for the Agentic Era”: probe actively like nmap, but land at conclusions like “this is an MCP server exposing 14 tools, two of which can run commands” rather than “port 8000 is open”.
2. The four-stage pipeline
| Stage | What it does | Input → output |
|---|---|---|
| Discover | Shodan queries pull candidate hosts, httpx filters the live ones | Queries / CIDR → live endpoints |
| Fingerprint | Nuclei templates + live HTTP probes: protocol, framework, auth, tools, models, system prompts | Endpoint → structured fingerprint |
| Score | Compute a 0–10 risk score from exposure factors | Fingerprint → score + factor list |
| Test | Pick an attack engine by protocol; results stream back over WebSocket | Target → findings + request/response evidence |
Fingerprinting cross-checks three evidence streams: Shodan banner parsing (Server headers for the framework, status codes for auth), Nuclei findings normalization (five custom templates), and live probes (lightweight requests to protocol-fixed paths like /api/tags and /v1/models, with an 8-second timeout). First stream to find a field wins it — a system prompt, for instance, is extracted from the MCP initialize response or the prompt-leak template, and flagged the moment it shows up.
3. What the 32 queries look for
The query set is organized around 11 protocol families:
| Protocol | Detection signal | Example query |
|---|---|---|
| MCP | JSON-RPC + capabilities, /mcp/sse | "Model Context Protocol" |
| Ollama | Port 11434, banner string | port:11434 "Ollama is running" |
| OpenAI-compatible | /v1/models, /v1/chat/completions | http.html:"/v1/models" port:8000 |
| LangServe | Playground markers | http.html:"langserve" "playground" |
| OpenClaw | Control dashboard title, port 18789 | http.title:"Clawdbot Control" |
| Open WebUI / LibreChat | Page titles | http.title:"Open WebUI" |
| Gradio | Title, footer watermark, favicon hash | http.favicon.hash:945408572 |
| Streamlit | Title, favicon hash | http.favicon.hash:-335242539 |
| ComfyUI / SD WebUI | Titles, ports | http.title:"ComfyUI" |
| HuggingFace TGI | HTML markers | http.html:"huggingface" http.html:"model" |
| Generic inference | /api/generate, /api/tags | http.html:"/api/generate" |
The queries are not improvised. The source comments list their origins: Knostic’s MCP-Scanner research, Praetorian’s Julius LLM fingerprinting, the Cisco / SentinelOne / FuzzingLabs Ollama exposure studies, and UpGuard’s Streamlit / ComfyUI exposure reports — the query bank is effectively a compilation of industry exposure research.
Two details from the source: the README’s protocol table covers only 30 of the queries, while the code ships 32 — the missing two are oobabooga’s text-generation-webui and a generic /v1/chat/completions query. In the other direction, the banner-detection code has an autogen branch, but no query preset exists for it: it can recognize one, it just can’t go looking for one.
4. How the risk score is computed
The weights below are all verified against compute_risk_score:
| Factor | Points |
|---|---|
| No authentication | +4.0 |
| Auth status unknown | +1.0 |
| 10+ tools exposed | +2.0 |
| 5+ tools exposed | +1.0 |
| Each critical-risk tool | +1.0 |
| Each high-risk tool | +0.5 |
CORS open to * |
+1.0 |
| No TLS | +0.5 |
| System prompt leaked | +0.5 |
| Models exposed | +1.0 |
| Uncensored model detected | +2.0 |
| Open signup | +1.5 |
| Each dangerous combo | +1.0 |
The total is clamped to 0–10, with tiers at critical ≥9.0, high 7.0–8.9, medium 4.0–6.9, low 1.0–3.9 and info <1.0.
Worth noting in the design: no-auth is the single largest factor at +4, matching the intuition that an exposed AI service is already the worst case; unknown auth still earns +1 so unverified endpoints don’t sink below notice; and dangerous combos add independently — no auth plus a command-execution tool (exec_no_auth), full database read/write (db_read_write), full file read/write (file_read_write).
Three findings from the scoring code:
- Auth detection is coarse: an HTTP 200 is taken as “no auth”. Plenty of login-walled services return 200 on their landing page, so they get marked no_auth and +4 — fake exposed services will mix into the list.
- Combos are substring matches: a tool name containing “admin” triggers admin_no_auth. A tool called manage_notes will be treated as an admin tool.
- Clamping saturates: the score caps at 10, so a 14-point endpoint and a 10-point endpoint display the same number and the ranking loses resolution.
5. The attack engines
The MCP engine runs seven phases:
| Phase | What it does | Success test |
|---|---|---|
| Recon | initialize handshake + tools/list; regex-classifies tools into 8 categories | — |
| Unauth tool calls | Calls the first N tools with minimal schema-built arguments | Response contains no auth-error keywords |
| Sensitive file reads | Hits file_read tools with /etc/passwd, .env, /proc/self/environ and more | Response matches content signatures |
| Command execution | Runs id, whoami, env against exec tools | Response contains uid=, /bin/, etc. |
| SSRF | Points http tools at cloud metadata addresses | Response contains metadata signatures |
| Prompt injection | Feeds 6 injection payloads into string parameters | Response matches ≥2 of 14 prompt indicators |
| DB extraction | Feeds 6 SQL payloads to db tools | Response shows schema markers or syntax errors |
Depth comes in four levels — quick / standard / deep / exhaustive — with standard as the default and a 20-step cap, 0.2 seconds between steps. The SSRF targets include 169.254.169.254, Google’s metadata service, Alibaba Cloud’s 100.100.100.200 and localhost. The Ollama engine goes after model listing, weight extraction and prompt injection; the OpenClaw engine targets the control dashboard.
One finding from the attack code: verdicts are keyword heuristics with wide fallbacks — a file read, for instance, counts as successful whenever the response is non-error and non-empty (a string longer than 20 characters, or any non-empty list). Normal business responses satisfy that all the time. The engine is built to quickly surface targets that are obviously broken, not to replace human review — results still need line-by-line verification.
6. Where the AI is
The README and the environment template both carry ANTHROPIC_API_KEY, annotated “optional — enables AI-powered attack analysis”, and the ROADMAP vision promises an “autonomous red-team agent (Claude-powered)” that reads a fingerprint and reasons about attack chains. But reading the current code: the key is declared in config.py and mentioned in .env.example and the Modal deployment docs — no line of code ever reads it. The attack engines are hard-coded scripts with no model calls anywhere.
So the AI currently lives in the roadmap. That is, if anything, the honest part of the design: discovery, fingerprinting and scoring don’t need a model — deterministic rules are more controllable and reproducible. The genuinely hard step, reading a fingerprint and reasoning about attack chains, is left in the ROADMAP until the capability earns its place. Don’t be misled by the “AI-powered” label.
7. Getting started
Docker Compose brings up four services (MongoDB, Redis, the FastAPI backend and the frontend); the .env needs at least SHODAN_API_KEY. Redis can degrade to an in-memory fallback, and Nuclei is only required for active scanning. There are two scan modes: discovery scans (query presets or custom Shodan queries, optionally scoped to a CIDR range) and active scans (httpx plus custom templates against a given IP range, default ports 80/443/3000/8000/8080/8443/8888).
Search uses Shodan-style syntax:
| Syntax | Meaning |
|---|---|
protocol:mcp auth:none |
Unauthenticated MCP servers |
risk:critical tool:exec_code |
Critical endpoints with a code-execution tool |
has:system_prompt |
Endpoints with a leaked system prompt |
country:US port:11434 |
Exposed Ollama instances in the US |
Concurrency is capped at 3 scans and 5 attacks at once, with 10 requests/minute on the creation endpoints; heavy workloads can be dispatched to Modal serverless containers. Each endpoint’s detail page shows the full fingerprint, lets you re-trigger enrichment, and opens the Attack panel with streaming results.
8. Before you use it
- Authorization: the official warning is explicit — authorized testing only. Scans and attacks send real requests to real targets.
- False positives: scoring and attack verdicts are heuristics throughout. “Critical” in the list does not mean a confirmed vulnerability.
- Cost: the Shodan API is metered per query; the code self-throttles at one second between pages, but running all 32 queries still consumes real quota — budget it yourself.
- Operations: MongoDB + Redis + Nuclei + a frontend. It’s a small platform, not a one-liner.
- 32 Shodan queries across 11 protocol families; the README table lists only 30
- Scoring: no-auth is the biggest factor at +4.0; critical at ≥9.0; four dangerous combos
- MCP engine, 7 phases: recon → unauth tool calls → file reads → command exec → SSRF → prompt injection → DB extraction
- 4 depths (quick/standard/deep/exhaustive), standard by default with a 20-step cap
- Concurrency: 3 scans / 5 attacks / 10 requests per minute on creation endpoints
- AI status: ANTHROPIC_API_KEY is declared but never read; the Claude attack reasoning lives in the ROADMAP
- Resources: Repository · Discovery engine docs · Nuclei templates