AIMap: nmap for the Agentic Era

The one-line summary

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:

  1. 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.
  2. 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.
  3. 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.
Key numbers
  • 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
评论Comments