◎
The Shadow AI Radar
Observations of internet-facing AI services · public dataset
Checking feed status…Scan your infrastructure →
AI services observed
22,924
of which 1,403 confirmed exposed (answered with no auth)
New observations · 24h
1,002
≈ 42 new every hour
Open at last re-test · no auth
225
proven exposures, each host re-tested at most once in 24 h
Verdict split · 51,741 probed
225 open3,617 protected47,899 not assessed
Observations by hosting location
Bubble size = how many · click one to filter
New observations · 30-day trend
total 22,104avg/day 737peak 1,835 · 10-18
1,83591802026-09-27: 1,638 new2026-09-28: 1,146 new2026-09-29: 899 new2026-09-30: 1,563 new2026-10-01: 861 new2026-10-02: 861 new2026-10-03: 1,487 new2026-10-04: 1,190 new2026-10-05: 1,061 new2026-10-06: 819 new2026-10-07: 1,494 new2026-10-08: 0 new2026-10-09: 0 new2026-10-10: 0 new2026-10-11: 0 new2026-10-12: 0 new2026-10-13: 0 new2026-10-14: 0 new2026-10-15: 0 new2026-10-16: 0 new2026-10-17: 0 new2026-10-18: 1,835 new2026-10-19: 123 new2026-10-20: 1,207 new2026-10-21: 1,081 new2026-10-22: 1,003 new2026-10-23: 962 new2026-10-24: 928 new2026-10-25: 954 new2026-10-26: 992 new1,83599209-2710-26
Hover any point for that day’s exact count · source: Certificate Transparency + Shodan · © Shodan, which owns that data; EchelonGraph claims no copyright in it
Live discovery feed
newest first · scroll for more
Tuning in to the Certificate Transparency stream…
Top hosting locations
Click a row to filter the board · hosting location from Shodan data, © Shodan, which owns that data; EchelonGraph claims no copyright in it
By category · 12 types
Observations per category · click a tile to filter the board
Click a product to filter the board · from Shodan data, © Shodan, which owns that data; EchelonGraph claims no copyright in it
AI-Exposure Radar · MCP servers

MCP servers, adjudicated

Changed 30 September 2026: the MCP server figure on this page is now the adjudicated count below. It had been the Shadow AI radar's count of MCP-server observations. On that day, all but two of them were Shodan search results addressed by IP and port, matched on MCP terms in the HTTP response Shodan recorded (Shodan data, © Shodan), and the two were certificate hostnames. That radar sends no MCP request, so none of them was ever checked as an MCP server. The count is still on the board, labelled not assessed.

Of 16,921 hostnames checked as MCP candidates, 1,156 validated as protected under RFC 9728 and 15,765 are not assessed. Our own 3 hosts (control servers) are excluded from every count here.

Measured from 25 September 2026 to 26 October 2026 (UTC dates). Counted 26 October 2026, 20:19 UTC. The radar is checking; its last completed check, across all its services, was 26 October 2026, 20:07 UTC.

Protected, RFC 9728 validated
1,156

Refused our request with HTTP 401 or 403, and its OAuth protected-resource metadata (RFC 9728), read from the same origin, names exactly the endpoint we asked and at least one authorization server.

Metadata found at:
  • the metadata URL named in the 401 or 403 challenge, on the same origin: 1,047
  • /.well-known/oauth-protected-resource/mcp: 50
  • /.well-known/oauth-protected-resource: 59
Not assessed
15,765

Everything else, each for the reason below. Not assessed is not unprotected, and it is never a finding of exposure.

Not assessed, by reason (15,765 in all)
Asked for credentials, but the metadata did not validate
Did not validate is not unprotected: every server counted here refused our request with HTTP 401 or 403. A resource_mismatch server did challenge for OAuth; the resource its metadata names is not the endpoint we asked.
1,715
Metadata names a different resource resource_mismatch
The metadata's resource is absent, or is not identical to the endpoint we asked (RFC 9728 §3.3).
449
Metadata on another origin cross_origin_pointer
The challenge points to metadata on another origin. We record that and never request it.
94
No metadata found bare_challenge_no_prm
The challenge names no metadata URL, and neither well-known metadata URI answered 2xx.
1,127
Metadata URL did not answer pointer_unreachable
The same-origin metadata URL the challenge names did not answer 2xx in full.
14
Metadata pointer not requested pointer_invalid
The challenge's metadata value is not a URL we will request (RFC 9728 §5.1, RFC 9110 §11.2).
7
No authorization server named no_authorization_servers
The metadata names no authorization server; MCP requires at least one.
5
Well-known metadata request got no answer wellknown_unreachable
A well-known metadata request got no complete HTTP answer (a timeout, a refused connection, TLS).
7
Metadata answer not a document metadata_invalid
The metadata answer was not a 200 with a JSON object within our size cap (RFC 9728 §3.2).
12
Asked for credentials before our RFC 9728 check existed challenge_unadjudicated
An HTTP 401 or 403 recorded before we read protected-resource metadata. Each is re-checked in rotation under the current rule.
241
Identified as an MCP server, and did not ask for credentials at the handshake identified_no_challenge
It answered our server/discover request, the older initialize handshake or the older SSE stream as an MCP server does, and did not ask for credentials. This is normal in MCP: authorization is optional in the specification, and a server can answer these requests and still require credentials when a tool is called, at tools/call, which EchelonGraph never sends. So this is not a finding of exposure.
485
Answered, but not as an MCP server not_identified_as_mcp
It answered HTTP, but nothing in the answer identified an MCP server: a web page, an error, a body that is not JSON-RPC.
2,220
No HTTP answer no_http_answer
We could not reach the service: DNS, the connection, TLS or a timeout.
11,104
Protocol era, of all 16,921
answered server/discover (not proven modern-only) modern26
dual-era, a lower bound: the server also named an initialize-era version dual8
legacy: identified by the initialize handshake or the older SSE stream legacy384
unknown: nothing identified its revision (every credential challenge is here) unknown14,584
not yet re-checked since the era probe (#2314) not_measured1,919
Transport, of all 16,921
Streamable HTTP: identified by a POST to /mcp streamable_http375
HTTP+SSE, the deprecated transport: identified by the first event of GET /sse legacy_sse43
unknown: nothing identified a transport unknown14,584
not yet re-checked since the era probe (#2314) not_measured1,919

How these MCP counts are made

Where the hosts come from. Every host counted here came from EchelonGraph’s own Certificate Transparency feeds: hostnames in newly issued TLS certificates, which we read from the public CT logs ourselves and from a public CT search index. A hostname is sent an MCP check only when mcp or mcpserver is one of its labels, or a hyphen-separated part of one: so mcp.example.com and mcp-server.example.com are checked, and xmcpy.example.com is not. Shodan is not a source for these counts. Its MCP results are addressed by IP and port, and we do not send them an MCP check: the MCP check is a POST, and our scan opt-out register cannot say whose server a bare address is, so an owner who opted out could not stop it. Hosts under echelongraph.io, the control servers we run to test this check, are excluded from every count. So is every host whose owner opted out of scanning: we do not check it again while the opt-out stands, so its last verdict could not be re-checked, and it is withheld rather than shown as current.

What we send. To each candidate, only these requests, each carrying our User-Agent and a signed receipt, and each asked of the scan opt-out register before it is sent:

  • one POST of a JSON-RPC server/discover request to /mcp, always first. It asks which protocol versions the server supports and, under the 2026-07-28 revision, opens no session. A server that answers it with a result, or with an error that revision defines, is sent no second POST;
  • a second POST, the older initialize handshake, only when server/discover is refused with an HTTP 4xx status other than 401, 403, 405 or 429 that is not a web page, or with a JSON-RPC error;
  • a DELETE to /mcp, only if a POST’s reply opened a session, to release it;
  • if a POST is refused with HTTP 401 or 403, at most two GETs of the server’s OAuth protected-resource metadata (RFC 9728) on the same host: the metadata URL the challenge names, once, only if it is on the same origin; or, when it names none, /.well-known/oauth-protected-resource/mcp and then /.well-known/oauth-protected-resource only if the first answered with an HTTP status other than 2xx. No redirect is followed;
  • one GET of /sse, the stream of the deprecated HTTP+SSE transport, only when /mcp identified nothing and last answered 400, 404 or 405. We read at most its first event and close the connection.

We never send tools/list, tools/call, resources/read, prompts/get or any other MCP method.

Why no MCP server is ever counted as open. In MCP the handshake and the authorization boundary are different places. A client has to be able to ask a server what it supports before it can learn how to authenticate, so a server can answer server/discover or the initialize handshake for anyone and still require credentials when a tool is called. Only tools/call, which runs somebody’s tool, could tell the two apart, and we never send it. So this check records a server as protected, on the RFC 9728 rule above, or as not assessed, with its reason; it never records one as open. Authorization is also optional in the MCP specification, so a server that asks for no credentials is not violating it.

When. The verdicts counted above were last checked from 25 September 2026 to 26 October 2026 (UTC dates): the oldest and the newest check among them. Hosts are re-checked in rotation, so each count is as of those dates.

Go deeper

The live console, methodology & category playbooks

Everything behind the dashboard — the filterable feed with per-row briefings, the risk categories with attacker playbooks, our reproducible method, documented incidents, compliance mappings, and how to cite the dataset.

Live observation feed

Every match, filterable — click a row for the attacker playbook

🔒 Why endpoint addresses are locked+

Every row describes a computer that belongs to someone else. The publishable part — what kind of AI service it is, who hosts it, which country it sits in, which product it runs, and whether it answers without a password — is open on this page for anyone to read, cite or crawl. The one part we hold back is the exact address: the IP and port, plus the request path our scanner used. Published together, those stop being research and start being a targeting list.

The lock is enforced on our servers, not in your browser — the address is simply never sent. Unlocking one endpoint requires accepting a short access agreement, happens one row at a time, and is recorded. What we record when you unlock →

Tuning radar to CT log stream…

What we monitor · 130+ detection patterns

Risk categories, each with its attacker playbook

Click a category to expand the attacker playbook, blast radius, remediation steps and CVE / OWASP references. Verified counts are confirmed-reachable observations. The MCP Server card shows the adjudicated MCP counts instead: protected, of the hostnames checked.

RAG Pipeline
Retrieval-Augmented Generation endpoints reveal the topology of your knowledge stack.
Unauthenticated endpoints → wholesale document exfiltration
0verified
0observed
What an attacker learns

A subdomain like internal-rag-pipeline.acme.com tells an attacker that you run a RAG architecture, almost always on a default port (FastAPI/Flask 8000–9000). It confirms three things at once: (1) you have an embedding store reachable over HTTPS, (2) you have a backing LLM connected to it, and (3) somewhere in that stack there is privileged data — code, contracts, customer records — being indexed for retrieval.

Attacker playbook
  1. Enumerate the discovered hostname for /docs, /openapi.json, /retrieve, /query, and /health.
  2. Confirm whether the endpoint is unauthenticated by sending an empty similarity-search request.
  3. If reachable, exfiltrate top-k documents with crafted high-recall queries.
  4. Pivot: discover associated *-vector-db-* and *-llm-proxy-* subdomains via the same CT log.
  5. Persistence: poison the embedding store with adversarial documents to manipulate downstream LLM output.
Blast radius

Wholesale data exfiltration of every document indexed by the pipeline — typically internal wikis, support tickets, contracts, or source code. Successful poisoning attacks turn the LLM into a controlled puppet for every employee that consumes its answers.

Remediation
  • Put RAG endpoints behind a private VPC + IAP / SSO only — never on the public internet.
  • Use wildcard certificates (*.internal.acme.com) so individual services do not appear in CT logs.
  • Subscribe to your own CT logs with crt.sh / Censys and alert on every new internal hostname.
  • Add an authentication middleware to FastAPI / Flask before any /retrieve route.
  • Enable mutual TLS between the RAG service and the embedding store + LLM.
Subdomain patterns matched
*rag**retrieval**knowledge**kb-**eval-**rag-customer**rag-sales*
References
Vector Database
Standalone vector stores (Milvus, Qdrant, Chroma, Weaviate) commonly ship with no auth.
Ships with no auth — anonymous read / write / DELETE on your corpus
145verified
765observed
What an attacker learns

Hostnames matching milvus-*, qdrant-*, chroma-*, weaviate-* signal a bare vector database — not a managed service. These products default to open access for developer convenience; the vast majority of internet-exposed instances accept anonymous reads and writes on their well-known ports (Milvus 19530, Qdrant 6333, Chroma 8000, Weaviate 8080).

Attacker playbook
  1. Hit /collections (Qdrant, Chroma) or list_collections (Milvus) without auth — confirm enumeration.
  2. Pull top-k embeddings from the largest collection, store the vectors locally.
  3. Use embedding-inversion (vec2text, GEIA) to reconstruct the source text from stolen embeddings.
  4. Inject adversarial vectors that hijack downstream retrieval (data poisoning).
  5. DELETE /collections wipes the entire knowledge base — single-call destructive op.
Blast radius

Stealing embeddings is provably equivalent to stealing the documents they were built from. A successful read attack therefore exfiltrates years of internal corpus content. A successful write attack lets the attacker dictate what the company's own AI tells employees.

Remediation
  • Bind the vector DB to a private subnet only (use SecurityGroup / NSG / GCP firewall).
  • Enable the database's native auth (Milvus RBAC, Qdrant API keys, Weaviate API tokens).
  • Front the DB with an authenticated proxy (e.g. Envoy + JWT) for any cross-service access.
  • Rotate API tokens via your secret manager; never hard-code in client code.
  • Audit every CREATE/DELETE collection event to a SIEM.
Subdomain patterns matched
*milvus**qdrant**chroma**weaviate**vector-db**pinecone*
References
LLM Proxy
Internal proxies routing to OpenAI, Anthropic, or self-hosted models — token-bearing surfaces.
Holds your model API keys — token theft + six-figure bill abuse
936verified
4,832observed
What an attacker learns

Subdomains like openai-internal.startup.io, claude-bridge.acme.com, anthropic-proxy.fintech.ai are the chokepoints where engineering teams stash their model API keys. Every employee request flows through them, which means the proxy holds long-lived API tokens for the upstream model provider.

Attacker playbook
  1. Probe /v1/chat/completions, /v1/messages, /openai/v1/* — proxies usually mirror the upstream API shape.
  2. If unauthenticated, submit prompt-jailbreak payloads to confirm the upstream is reachable.
  3. Burn the company's token budget at scale (financial DoS — six-figure monthly bills are common).
  4. Pivot: extract system prompts and tool definitions through prompt-injection on the proxy.
  5. Use the proxy as a free LLM for further attacker-side automation (model laundering).
Blast radius

A direct hit on a single LLM proxy can cost a company hundreds of thousands of dollars in unbudgeted model spend, leak the company's system prompts (which encode product strategy), and expose any tool integrations wired into the agent layer.

Remediation
  • Require an Authorization Bearer header on every proxy route — reject anonymous calls with 401.
  • Issue per-employee proxy tokens via your IdP (Okta, Azure AD); never share a master key.
  • Set per-tenant + per-user budget caps and alert on anomalies in token usage.
  • Strip / sanitise system prompts from server responses; never echo them back.
  • Put the proxy behind your edge auth (Cloudflare Access, IAP) — not on the open internet.
Subdomain patterns matched
*gpt-**claude-**anthropic-**openai-**openai.**llm-proxy**llm-gateway**llm-api**ai-proxy**model-proxy*
References
Model Registry
MLflow / Ray / SageMaker registries leak model artifacts, prompt templates, and training data.
RCE — Ray CVE-2023-48022 (ShadowRay), exploited in the wild
123verified
320observed
What an attacker learns

Hostnames like mlflow-internal.acme.com, ray-dashboard.startup.io, model-registry.fintech.ai expose the build system for AI. These dashboards show every registered model version, every experiment's parameters and metrics, every artifact path, and — critically — the raw prompts and configurations a RAG / agent pipeline shipped to production.

Attacker playbook
  1. MLflow: hit /api/2.0/mlflow/experiments/search to enumerate all experiments without auth (the older experiments/list RPC was removed in MLflow 2.0).
  2. Download artifact files via /get-artifact?path=... — known path traversal in older versions (CVE-2024-1483).
  3. Ray: hit /api/jobs to submit arbitrary Python (CVE-2023-48022 — ShadowRay RCE).
  4. Pivot: use leaked artifact paths to fingerprint internal cloud storage (S3 / GCS bucket names).
  5. Persistence: register a malicious model as 'production' so the next deploy ships attacker code.
Blast radius

Full model intellectual-property theft + fine-tuning data exposure + remote code execution on the head node. The Ray exposure alone — confirmed at 2,000+ public clusters — is consistently one of the top AI security incidents of the year.

Remediation
  • Run MLflow / Ray behind your VPN or IdP; never expose them on a public LB.
  • Patch MLflow ≥ 2.10.1 (CVE-2024-1483 path traversal) and Ray ≥ 2.8.1 (CVE-2023-48022 RCE).
  • Enable Ray's --auth flag and MLflow's basic auth plugin; rotate credentials via secrets manager.
  • Sign model artifacts (Sigstore, in-toto) so a malicious registration is rejected at deploy time.
  • Stream registry audit logs to a SIEM and alert on new artifact downloads from unknown IPs.
Subdomain patterns matched
*mlflow**ray**model-registry**registry**training**fine-tune*
References
AI Agent
Autonomous agents (LangChain, AutoGen, agent-orchestrator) with tool-execution surfaces.
Tool layer = shell + internal-API access via one prompt injection
0verified
10observed
What an attacker learns

Subdomains like agent-orchestrator.acme.com or langserve-staging.startup.io expose an autonomous agent — an LLM with tools. The tools are the dangerous part: shell access, filesystem access, internal API calls, browser automation, even cloud account credentials.

Attacker playbook
  1. Hit /agents/run, /chains/run, /invoke — most LangServe deployments expose these by default.
  2. Send a prompt-injection that triggers the tool layer to run arbitrary commands.
  3. Use the agent as a confused deputy to call internal APIs the attacker cannot reach directly.
  4. Exfiltrate credentials by asking the agent to 'help debug' an environment variable.
  5. Persistence: store a malicious memory entry that re-triggers on every future agent invocation.
Blast radius

Anything a tool the agent has access to can do — usually filesystem read, internal HTTP, and shell execution. A leaked agent endpoint is a direct foothold inside your VPC, no exploit required.

Remediation
  • Treat the agent as untrusted and apply least-privilege to its tool credentials.
  • Wrap every tool call in policy-engine middleware (OPA, Cerbos) before execution.
  • Disable shell / filesystem tools in production; route them via a sandboxed worker only.
  • Never expose the orchestrator on a public LB — front it with SSO and rate-limit per user.
  • Log every tool call with full prompt + response to your SIEM for prompt-injection forensics.
Subdomain patterns matched
*ai-agent**langserve**langchain**autogen**agent-orchestrator**ai-copilot**agentic**crewai*
References
Prompt Cache
Redis / Memcached / disk caches storing prompt + response pairs verbatim.
Redis / Memcached no-auth — every cached prompt readable
0verified
0observed
What an attacker learns

Hostnames like llm-prompt-cache.acme.com or embeddings-gateway.startup.io are typically a Redis or Memcached instance fronting an LLM. The cache keys are full user prompts; the values are full model responses. Every cache hit is a transcript of an employee asking a private question.

Attacker playbook
  1. If Redis: connect anonymously, run KEYS * — every cached prompt is now visible.
  2. Pull cached values to reconstruct what employees asked the AI (HR queries, code, contract drafts).
  3. Inject adversarial cache entries so the next employee sees attacker-controlled output.
  4. Pivot: use the cache contents to fingerprint other internal services they reference.
Blast radius

A historical record of every privileged conversation a company's employees had with their AI tooling — typically the most sensitive material in the org, written in plain language. Public exposure is a near-automatic regulator escalation under GDPR / DPDP / HIPAA depending on content.

Remediation
  • Bind Redis / Memcached to localhost or a private VPC subnet only.
  • Require AUTH on every cache (rediss:// + ACL users in Redis 6+).
  • Store only hashed prompt keys + encrypted response values; rotate encryption keys quarterly.
  • Set short TTLs (≤ 5 minutes) on cached responses to reduce blast radius.
  • Audit cache contents for PII / PHI before turning the cache on at all.
Subdomain patterns matched
*cache**embeddings-gateway**prompt-cache**redis-llm*
References
Notebook Server
Jupyter / JupyterHub notebooks with interactive code execution, shell access, and stored credentials.
Arbitrary code execution — actively crypto-mined (Qubitstrike, TeamTNT)
84verified
2,339observed
What an attacker learns

Subdomains like jupyter-internal.acme.com, notebook-staging.startup.io, or lab-ds.fintech.ai expose a full interactive Python execution environment. Jupyter notebooks ship with no authentication in single-user mode. Every running notebook has filesystem access, a built-in terminal, and typically contains API keys, database passwords, and cloud credentials embedded in code cells or .env files in the working directory.

Attacker playbook
  1. Access the notebook UI — if no auth, you have immediate code execution via a new Python cell.
  2. Open the built-in terminal: Full shell access as the notebook server user (often root in containers).
  3. Search cells and filesystem for credentials: AWS keys in ~/.aws/, .env files, hardcoded API tokens.
  4. Install crypto miners (Qubitstrike, TeamTNT campaigns actively target exposed Jupyter servers).
  5. Pivot: use the notebook's network position to scan internal services unreachable from the internet.
Blast radius

Arbitrary code execution on the host machine with full filesystem access. Exposed notebooks are actively exploited for cryptocurrency mining and as pivot points into internal networks. Stored credentials in notebook cells provide lateral movement to cloud accounts, databases, and internal APIs.

Remediation
  • Never expose Jupyter to the public internet — use JupyterHub with SSO/OAuth behind a VPN.
  • Set c.NotebookApp.token and c.NotebookApp.password in jupyter_notebook_config.py — never run tokenless.
  • Run notebooks in isolated containers with no-root, read-only filesystem where possible.
  • Use managed notebook services (Vertex AI Workbench, SageMaker Studio) that handle auth natively.
  • Strip credentials from notebook cells before committing — use environment variables or secret managers.
Subdomain patterns matched
*jupyter**jupyterhub**notebook**nb-**jupyter-lab**lab-ds**ipynb*
References
AI Workflow Builder
No-code AI builders (OpenWebUI, Flowise, Dify) storing API keys for multiple LLM providers and full chat histories.
RCE — Flowise CVE-2025-59528 + multi-provider API-key theft (LLMjacking)
66verified
6,440observed
What an attacker learns

Subdomains like chat-ai.acme.com, flowise.startup.io, or dify-internal.corp.ai expose a full AI workflow builder. These platforms store API keys for OpenAI, Anthropic, Azure, and local models in a single dashboard. Chat histories contain every question employees asked the AI — often including PII, financial data, legal discussions, and source code. Tool integrations provide access to internal databases, CRMs, and file systems.

Attacker playbook
  1. Access the UI — many instances use default credentials or have registration open to anyone.
  2. Navigate to Settings/API Keys — extract stored OpenAI, Anthropic, Azure, Bedrock API keys.
  3. Browse chat histories — employees ask AI about sensitive internal matters (HR, legal, code).
  4. Exploit CVE-2025-59528 (Flowise RCE) to execute arbitrary code on the server.
  5. Use tool integrations (database, filesystem, API connectors) to access internal systems.
Blast radius

Multi-provider API key theft enables LLMjacking ($46K-$100K/day in unauthorized inference bills). Chat history exfiltration exposes every sensitive question employees asked the AI. RCE vulnerabilities (CVE-2025-59528) provide full server compromise. These are the fastest-growing shadow AI surface.

Remediation
  • Never expose AI workflow builders to the public internet — place behind VPN + SSO.
  • Disable open registration — require admin approval for new user accounts.
  • Rotate all stored API keys immediately if the instance was publicly accessible.
  • Patch Flowise to latest version (CVE-2025-59528 RCE fix).
  • Enable audit logging for all chat sessions and tool invocations.
  • Use EchelonGraph to monitor for new instances appearing in CT logs.
Subdomain patterns matched
*openwebui**open-webui**flowise**dify**n8n-ai**ai-workflow**ai-builder**chat-ui**chatbot-*
References
Inference Server
TorchServe, TF Serving, vLLM, and TGI model-serving endpoints with management APIs exposed.
RCE — ShellTorch CVE-2023-43654 + malicious model registration
49verified
425observed
What an attacker learns

Subdomains like inference-api.acme.com, torchserve.startup.io, or vllm-prod.fintech.ai expose production model serving infrastructure. Management APIs allow registering/unregistering models, viewing loaded model metadata, and accessing inference endpoints. TorchServe binds gRPC management ports to 0.0.0.0 by default (CVE-2024-35199), making internal management APIs publicly accessible.

Attacker playbook
  1. Probe management API: GET /models (TorchServe), GET /v1/models (vLLM/TGI) to enumerate loaded models.
  2. Register a malicious model via POST /models (TorchServe management API) — models can execute arbitrary code.
  3. Exploit CVE-2024-35198 (TorchServe path traversal) to load models from attacker-controlled URLs.
  4. Chain ShellTorch (CVE-2023-43654): SSRF + unsafe deserialization → full RCE on the server.
  5. Use inference API to extract model weights via repeated queries (model extraction attack).
Blast radius

Model poisoning via unauthorized model registration causes every downstream consumer to serve attacker-controlled output. ShellTorch RCE chain provides full server compromise. Model extraction through repeated inference queries enables intellectual property theft of proprietary AI models.

Remediation
  • Bind management APIs to localhost only — never expose gRPC ports 7070/7071 (TorchServe) publicly.
  • Patch TorchServe ≥ 0.11.1 (CVE-2024-35199, CVE-2024-35198, CVE-2023-43654).
  • Enable token-based authorization on TorchServe (available since v0.11.1).
  • Place inference endpoints behind an API gateway with rate limiting and authentication.
  • Only load model archives (.mar) from trusted, verified artifact registries.
Subdomain patterns matched
*torchserve**tf-serving**inference-**model-serve**serving-**prediction-**vllm**tgi-**hf-inference**text-gen*
References
ML Pipeline
Apache Airflow and ML pipeline orchestrators leaking DAG code, credentials, and execution logs.
Every connected DB / cloud credential exposed — Airflow CVE-2024-45784
0verified
106observed
What an attacker learns

Subdomains like airflow.acme.com, dag-scheduler.startup.io, or pipeline-internal.corp.ai expose the orchestration control plane for ML training pipelines. Airflow dashboards reveal every DAG definition (pipeline code), connection credentials (database passwords, cloud API keys), and task execution logs — which frequently contain plain-text secrets (CVE-2024-45784). Variable endpoints expose every stored secret in the system.

Attacker playbook
  1. Access the Airflow web UI — many instances ship with no auth or default admin:admin credentials.
  2. Browse DAGs: view full Python pipeline code including hardcoded database passwords and API keys.
  3. Read task logs: CVE-2024-45784 causes credentials to appear in plain text in execution logs.
  4. Access /api/v1/connections to enumerate every stored database and cloud credential.
  5. Trigger DAG runs with modified parameters to exfiltrate data or poison training pipelines.
Blast radius

Full credential exposure for every connected system — databases, cloud accounts, APIs, model registries. Pipeline manipulation enables training data poisoning that corrupts all downstream models. Task logs contain a historical record of every secret that ever transited the pipeline.

Remediation
  • Never expose Airflow to the public internet — bind to private VPC behind SSO.
  • Upgrade to Airflow ≥ 2.10.3 to fix CVE-2024-45784 (secret masking in logs).
  • Use Airflow Secret Backends (Vault, AWS Secrets Manager, GCP Secret Manager) — never store credentials in Connections/Variables directly.
  • Enable RBAC and restrict DAG-level access permissions.
  • Audit and rotate all credentials that may have been exposed in task logs.
Subdomain patterns matched
*airflow**dag-**ml-pipeline**data-pipeline**pipeline-**orchestrator-*
References
Data Annotation
Label Studio and Argilla annotation tools exposing training data, labels, and project configurations.
Path traversal to server files — Label Studio CVE-2025-25295
0verified
969observed
What an attacker learns

Subdomains like label-studio.acme.com or annotation-tool.startup.io expose the data labeling platform used to prepare training datasets. These tools contain the raw training data (images, text, audio), annotation guidelines (which reveal model architecture intent), project configurations, and user accounts. CVE-2025-25295 allows reading arbitrary server files via path traversal.

Attacker playbook
  1. Access the Label Studio UI — many instances have open registration enabled.
  2. Browse projects to access raw training data (images, documents, audio recordings).
  3. Exploit CVE-2025-25295 (path traversal) to read /etc/passwd, .env, or cloud credentials.
  4. Exploit CVE-2025-25296 (XSS) to hijack admin sessions and steal authentication cookies.
  5. Modify annotations to poison training data — subtle label changes corrupt downstream models.
Blast radius

Training data theft reveals the content and scope of AI projects. Modified annotations create poisoned training data that degrades or manipulates model behavior. Path traversal vulnerabilities expose server credentials and internal configuration files.

Remediation
  • Update Label Studio to ≥ 1.16.0 (fixes CVE-2025-25295, CVE-2025-25296).
  • Disable open registration — require admin approval for new accounts.
  • Place behind VPN/SSO — never expose annotation tools to the public internet.
  • Enable Content Security Policy (not report-only mode).
  • Audit annotation history for unauthorized modifications.
Subdomain patterns matched
*label-studio**labelstudio**argilla**annotation-**labeling-**annotate-*
References
Model Storage
MinIO and S3-compatible object stores containing model weights, training datasets, and experiment artifacts.
Default creds minioadmin:minioadmin → full model + training-data theft
0verified
5,760observed
What an attacker learns

Subdomains like minio-ml.acme.com, artifacts.startup.io, or model-storage.corp.ai expose S3-compatible object storage — the default artifact backend for MLflow, Kubeflow, and most ML pipelines. These stores contain trained model weights (intellectual property worth millions), training datasets (often containing PII), experiment artifacts, and configuration files with cloud credentials. MinIO ships with default credentials (minioadmin:minioadmin).

Attacker playbook
  1. Try default credentials: minioadmin:minioadmin (MinIO default, rarely changed in dev environments).
  2. List buckets and enumerate contents — look for model-weights/, training-data/, experiments/.
  3. Download model weights: full IP theft of proprietary AI models.
  4. Download training data: PII, financial records, medical data used to train models.
  5. Upload a poisoned model to the production bucket — the next deploy ships attacker code.
Blast radius

Complete intellectual property theft of every model trained by the organization. Training data exfiltration may contain PII subject to GDPR/HIPAA breach notification. Model poisoning via artifact replacement turns the production AI into an attacker-controlled puppet.

Remediation
  • Change MinIO default credentials immediately — use a strong admin password.
  • Restrict bucket policies: never set public-read on buckets containing model artifacts.
  • Enable server-side encryption (SSE-S3 or SSE-KMS) for all stored objects.
  • Place MinIO behind a private VPC — never expose the console (port 9001) publicly.
  • Enable audit logging on all bucket operations and alert on downloads from unknown IPs.
Subdomain patterns matched
*minio**minio-**artifacts-**model-artifacts**model-storage**ml-storage*
References
Experiment Dashboard
TensorBoard and Weights & Biases dashboards revealing model architectures, hyperparameters, and training metrics.
Model architecture, hyperparameters + logged credentials leaked
0verified
1observed
What an attacker learns

Subdomains like tensorboard.acme.com, wandb-internal.startup.io, or metrics-ml.corp.ai expose experiment tracking dashboards. These reveal every model's architecture (layer configurations, attention heads, embedding dimensions), hyperparameter search spaces, training data distributions, loss curves, hardware configurations (GPU types, cluster size), and environment variables.

Attacker playbook
  1. Browse experiment runs to reconstruct the full model architecture and training recipe.
  2. Extract hyperparameters to replicate the model with lower cost (IP theft via architecture cloning).
  3. Identify the training data distribution to craft targeted adversarial examples.
  4. View hardware configuration to estimate the organization's AI investment and capabilities.
  5. Access environment variables logged during training — may contain cloud credentials.
Blast radius

Model architecture and hyperparameter theft enables competitors to replicate months of R&D. Training data distribution leaks reveal what data the model was trained on (potential regulatory exposure). Environment variables logged during training may contain cloud credentials.

Remediation
  • Place TensorBoard behind authentication — use --bind_all=false to restrict to localhost.
  • Enable Weights & Biases team-level access controls and private projects.
  • Never log environment variables or credentials during training runs.
  • Use managed experiment tracking with built-in auth (Vertex AI Experiments, SageMaker).
  • Audit experiment logs for accidentally logged secrets.
Subdomain patterns matched
*tensorboard**tb-**wandb**weights-biases**experiment-**metrics-ml*
References
MCP Server
Model Context Protocol servers connect AI clients to tools and data. MCP's authorization spec is optional, so a public one may or may not demand credentials.
Auth is optional in the spec — a server that runs tools for anonymous callers is a gateway to them
1,156protected
16,921checked
What this card counts

Protected and checked are the AI-Exposure Radar’s adjudicated MCP counts: hostnames checked as MCP candidates, and of those, the ones validated as protected under RFC 9728. Everything else it checked is not assessed, each for a stated reason. The full split, its dates and its method →

The Shadow AI radar’s own count in this category: Shodan search results addressed by IP and port (Shodan data, © Shodan) and certificate hostnames named like MCP servers. That radar sends no MCP request, so it assesses none of them for MCP authorization: 957.

What an attacker learns

Subdomains like mcp-server.acme.com, mcp-gateway.startup.io, or tool-server.fintech.ai host MCP (Model Context Protocol) endpoints — the emerging standard for connecting LLMs to external tools and data. A server that accepts anonymous tool calls runs them with its own access, reaching whatever its tools reach: files, databases, internal APIs. MCP has specified an authorization framework based on OAuth 2.1 since its 2025-03-26 revision, but the specification makes authorization optional, so whether a given public server demands credentials has to be checked, not assumed. Neither of our radars lists a server's tools or calls one. Our AI-Exposure Radar, which speaks MCP, counts a server as protected only when the server refuses its server/discover request, or the older initialize handshake sent only after that is refused, with HTTP 401 or 403 and its OAuth protected-resource metadata (RFC 9728), read from the same origin, names exactly the resource it was fetched for and lists at least one authorization server; anything short of that is recorded as not assessed, and it never reports an MCP server as open. The Shadow AI radar on this page does not assess MCP authentication: it never sends an MCP request, so a login page or an HTTP 401 or 403 it sees on such a host is recorded as not determined, not as protected. Rows it labelled before that rule keep their old label until they are re-checked.

Attacker playbook
  1. Send JSON-RPC 2.0 method 'tools/list' to enumerate every available tool.
  2. Call 'resources/list' to discover all connected data sources (databases, file systems, APIs).
  3. Execute tools directly via 'tools/call' — if the server has filesystem tools, read arbitrary files.
  4. Extract system prompts via 'prompts/list' and 'prompts/get'.
  5. Pivot: use database or API tools to access internal systems the MCP server is authorized to reach.
Blast radius

If an MCP server runs tool calls for anonymous callers, whoever reaches it acts with the server's own credentials, through whichever tools it exposes. Depending on how it was built, that can include internal databases, code repositories, CRM systems or cloud APIs. What is reachable is set by that server's tool catalogue and service account, not by the protocol, and our radar has not measured it for any host: it never calls a tool.

Remediation
  • Keep a local-only MCP server on localhost or a private network; serve a remote one only behind the MCP authorization spec or an authenticating gateway.
  • Require authorization on HTTP transports: implement the MCP authorization spec (OAuth 2.1, with RFC 9728 protected-resource metadata), or put an authenticating gateway in front of the server.
  • Apply least-privilege to the MCP server's service account.
  • Audit and restrict the tool catalogue: disable filesystem, shell, and database tools in production.
  • Log every tool invocation with full input/output to your SIEM for forensic analysis.
Subdomain patterns matched
*mcp-server**mcp-proxy**mcp-gateway**model-context**tool-server**mcp-bridge*
References
Reference

Method, incidents, compliance & citation

Detection patterns — the full catalogue+
Full detection-pattern catalogue(97 patterns across 14 risk categories)expand ↓

EchelonGraph monitors Certificate Transparency and Shodan banner-grab data for the following subdomain conventions. Each pattern is a literal substring match against freshly-issued certificate hostnames; a single hostname can match multiple categories. Publishing this list keeps the methodology auditable — anyone with access to crt.sh can reproduce our detection logic.

RAG Pipeline7
*rag**retrieval**knowledge**kb-**eval-**rag-customer**rag-sales*
Vector Database6
*milvus**qdrant**chroma**weaviate**vector-db**pinecone*
LLM Proxy10
*gpt-**claude-**anthropic-**openai-**openai.**llm-proxy**llm-gateway**llm-api**ai-proxy**model-proxy*
Model Registry6
*mlflow**ray**model-registry**registry**training**fine-tune*
AI Agent8
*ai-agent**langserve**langchain**autogen**agent-orchestrator**ai-copilot**agentic**crewai*
Prompt Cache4
*cache**embeddings-gateway**prompt-cache**redis-llm*
Notebook Server7
*jupyter**jupyterhub**notebook**nb-**jupyter-lab**lab-ds**ipynb*
AI Workflow Builder9
*openwebui**open-webui**flowise**dify**n8n-ai**ai-workflow**ai-builder**chat-ui**chatbot-*
Inference Server10
*torchserve**tf-serving**inference-**model-serve**serving-**prediction-**vllm**tgi-**hf-inference**text-gen*
ML Pipeline6
*airflow**dag-**ml-pipeline**data-pipeline**pipeline-**orchestrator-*
Data Annotation6
*label-studio**labelstudio**argilla**annotation-**labeling-**annotate-*
Model Storage6
*minio**minio-**artifacts-**model-artifacts**model-storage**ml-storage*
Experiment Dashboard6
*tensorboard**tb-**wandb**weights-biases**experiment-**metrics-ml*
MCP Server6
*mcp-server**mcp-proxy**mcp-gateway**model-context**tool-server**mcp-bridge*
Methodology — how each verdict is decided+

We publish the method so the dataset is independently verifiable. Anyone with access to Certificate Transparency and Shodan can reproduce our detection logic.

1. Data sources

Two public sources, no scraping, no proprietary signals:

  • crt.sh — the public Certificate Transparency search index. A cycle about once a minute; one cycle can take up to about 24 minutes when crt.sh queries time out.
  • Shodan — banner-grab enrichment (ASN, country, product). Swept every 12 hours, when Shodan query credits allow. Shodan data is owned by Shodan, which holds its copyright (© Shodan). EchelonGraph claims no ownership of it or copyright in it.

2. Verification states

Every observation carries one of seven liveness states, so we never publish unverified rows as exposures:

  • unverified — newly observed, probe pending
  • active — answered a protected endpoint with no credentials
  • authenticated — authentication observed: a 401/403, a login page, an authentication error in the response body, or a redirect to a login page. Flowise’s API-key refusal counts only from Flowise 3.0.1 on (see 3.)
  • inconclusive — answered, but no probe could tell whether it requires authentication; counted neither as exposed nor as secured
  • resolved — the host answered with an error status (4xx/5xx), a generic or non-AI web page, or an open API we judged intentionally public; or it did not answer at all (a timeout or a refused connection). No exposed response on the last probe — this is not evidence the service is secured.
  • unreachable — the hostname does not resolve
  • rechecking — re-verification in flight

3. Choosing the probe

Each candidate gets several read-only requests, not one. The site root; then up to three of the 22 endpoints we recognise, each one an endpoint the product’s own auth layer guards. Four of the 22: Jupyter /api/status, Ollama /api/tags, Weaviate /v1/objects?limit=0, MLflow /api/2.0/mlflow/experiments/search.

Four more, stated because they are requests too. An IP:port candidate that refuses plain HTTP is retried once over HTTPS. A candidate that answers open on one of those endpoint probes then has its landing page read — that read is how we tell a deliberately public demo from shadow IT, so it is not optional. And if the page redirects in JavaScript, which NAS and appliance web UIs commonly do, we follow it once to the host and port it names. Redirects are followed to a limit of five hops. And when a Flowise API answers with its API-key refusal (a 401), we send one more GET, to its public version endpoint /api/v1/version.

That refusal alone does not show the API is locked: Flowise 2.0.6 to 3.0.0 send it even where their own web UI reaches the API with no sign-in, using a request header we never send. So a version of 3.0.1 or later is counted as authentication observed; 2.0.6 to 3.0.0, a refused version endpoint, or a version we cannot read or place is not determined, unless the service’s own page refused us or showed a login page. The version itself is never published.

That choice is the whole method. An endpoint answering 200 on a hardened install can identify a product but never prove exposure — so we pick endpoints for what a secured instance refuses, and never read a single record to decide.

4. What we do not claim

Detection ≠ compromise. The radar surfaces exposed AI services; it does not assert any service was breached. Owners may have intentional public access (demos, public playgrounds). Some categories are deliberately not adjudicated rather than guessed — a missing verdict costs us coverage, a guessed one costs somebody else their reputation.

Documented shadow-AI incidents (2023–2025)+

Every incident is sourced to a primary advisory, vendor disclosure, or published research.

Compliance mapping — MITRE ATLAS · OWASP · NIST · EU AI Act · ISO 42001+
Shadow AI Detection

MITRE ATLAS — AML.T0011

MITRE ATLAS catalogues adversary techniques targeting ML systems. AML.T0011 covers the reconnaissance step this radar surfaces.

Read primary source ↗
Supply-Chain Vulnerabilities

OWASP LLM Top 10 — LLM07

Exposed MLflow registries, vector databases and Jupyter notebooks are textbook LLM07 instances.

Read primary source ↗
Risk monitoring

NIST AI-RMF — MS-2.1

NIST AI RMF MS-2 requires continuous monitoring of AI system risks. Shadow-AI exposure is a measurable external-attack-surface risk.

Read primary source ↗
Risk management + robustness

EU AI Act — Articles 9 + 15

High-risk AI systems must implement risk management and demonstrate accuracy + robustness. Exposed inference services evidence inadequate controls.

Read primary source ↗
Interested-parties disclosure

ISO/IEC 42001 — §A.8

ISO 42001 Annex A.8 requires managing information disclosure. Subdomain leaks via CT logs are an unmanaged disclosure pathway.

Read primary source ↗
Cite this dataset · public API · licence+
APA
EchelonGraph. (2026). Shadow AI Radar — Publicly Observed AI Infrastructure. Retrieved from https://echelongraph.io/shadow-ai-radar
BibTeX
@misc{echelongraph_shadow_ai_radar, author = {EchelonGraph}, title = {Shadow AI Radar — Publicly Observed AI Infrastructure}, year = {2026}, url = {https://echelongraph.io/shadow-ai-radar} }
Responsible disclosure
[email protected]
Licence
CC BY 4.0 for our own work only
Public API
/api/v1/public/shadow-ai-radar/stats

What the licence covers. CC BY 4.0 covers only EchelonGraph's own work in this dataset: its AI-category classifications, the verdicts of our own checks, its aggregate counts and its methodology. Shodan data (the country, product and hosting operator of each row found through Shodan) is © Shodan and is not relicensed under CC BY; reusing it requires Shodan's terms (https://static.shodan.io/legal/terms.html). Certificate details read from public Certificate Transparency logs through crt.sh (issuer, SAN count, validity date) are not relicensed under CC BY either.

See also

Sister intelligence surfaces

AI Threat Map →
Map of vector databases and AI services (Milvus, Qdrant, ChromaDB, Weaviate, Ollama and more), rebuilt once a day from Shodan searches.
Shadow Engine Map →
Ray dashboards and MLflow UIs broadcasting architecture and secrets.
AI Security Index →
Aggregated AI security posture across services, AI CVEs and compliance frameworks.
Seeing this scanner in your logs? It's us. Our Discovery Radars name themselves — like Googlebot — in the User-Agent of every HTTP request they send, for example EchelonGraph-<Radar>/1.0 (+https://echelongraph.io/surface-scanner; opt-out https://echelongraph.io/responsible-disclosure; [email protected]) or, from our radar prober, EchelonGraphBot/1.0 (+https://echelongraph.io/bot), and their HTTP requests to the hosts they check also carry a From: [email protected] header. Some checks are a single identified GET; others send several requests to one host. Confirming an MCP endpoint sends a POST asking the server which protocol versions it supports, a second POST with the older handshake only if the first is refused without a 2026-07-28 error, a DELETE to close any session a POST opened and, if a POST is refused with HTTP 401 or 403, up to two GETs of the server's OAuth protected-resource metadata on the same host; where neither POST finds an MCP endpoint, the older SSE transport's stream is requested with GET, only its first event is read, and the connection is closed. A server that answers the first POST with a DiscoverResult, or with an error the 2026-07-28 revision defines, opens no session and is sent no further POST, so it is not written to; if the POST is refused with HTTP 401 or 403, the metadata GETs above still follow. Confirming an exposed datastore needs a protocol-level exchange, and on Redis our client names itself so the connection is identifiable in your own CLIENT LIST. We never log in, submit credentials or exploit what we find. Who we are, exactly what each check sends, and how to opt out → A radar's HTTP requests to the host it checks also carry a signed receipt you can validate at /verify-scan.