Is Your Self-Hosted AI Agent Exposed? A Five-Minute Audit
The Intruder team scanned over two million hosts using certificate transparency logs and published the results in May 2026. The number worth sitting with: of 5,200+ internet-facing Ollama servers they sent a test prompt to, 31% answered. No credentials, no key, no challenge — just a working LLM endpoint belonging to someone who almost certainly thought it was private.
They also found 518 instances wrapping paid frontier models from Anthropic, OpenAI, Google, Deepseek and Moonshot — meaning a stranger could burn someone else’s API budget — and 90+ exposed n8n and Flowise instances across government, marketing and finance organisations.
Almost nobody exposes a service deliberately. The usual cause is a single mechanism that behaves differently from how everyone assumes, and this article is a five-minute audit to check whether it’s happened to you.
Why “I set up a firewall” isn’t the answer
Here’s the mechanism, and it catches experienced people.
If you run your agent in Docker and publish a port, ufw will not protect it. Not “might not” — will not, by design. From Docker’s own documentation:
“Docker routes container traffic in the
nattable, which means that packets are diverted before it reaches theINPUTandOUTPUTchains that ufw uses. Packets are routed before the firewall rules can be applied, effectively ignoring your firewall configuration.”
Docker states the incompatibility plainly: “Docker and ufw use firewall rules in ways that make them incompatible with each other.”
The second half of the trap is the publish default. Again from Docker:
“By default, when a container’s ports are mapped without any specific host address, the Docker daemon publishes ports to all host addresses (
0.0.0.0and[::]).”
So docker run -p 11434:11434 … — the command in most quickstart guides — publishes to every interface including the public one, and your ufw deny rule doesn’t apply. You ran two correct-looking commands and ended up with an open endpoint.
The audit
Four steps. Run them against your own server only — scanning hosts you don’t control is a different activity with different legal consequences.
Step 1 — What is listening, and on what address
On the server:
ss -tulpn
Read the Local Address:Port column. The distinction that matters:
-
127.0.0.1:11434— loopback only. Nothing outside the machine can reach it. -
0.0.0.0:11434or*:11434— every interface, including your public IP. -
[::]:11434— the same, over IPv6. Easy to miss if you only checked IPv4.
Anything on 0.0.0.0 is a candidate for exposure. It is not yet proof of exposure — a cloud provider’s network firewall may still be blocking it — which is what step 2 settles.
For containers, also check what Docker actually published:
docker ps --format '{{.Names}}\t{{.Ports}}'
0.0.0.0:11434->11434/tcp is the dangerous form. 127.0.0.1:11434->11434/tcp is the safe one.
Step 2 — Check from outside
Listening on 0.0.0.0 only matters if packets can reach it. Test from a machine that isn’t the server — your laptop on a different network, or any other host you control:
nmap -Pn -p 11434,3000,5678,8080 YOUR.SERVER.IP
open means reachable from wherever you ran that command. If your laptop is on the same VPN or LAN as the server, use a genuinely external network, or the test is meaningless.
No nmap to hand? A single port, no install:
nc -zv YOUR.SERVER.IP 11434
Common ports worth including: 11434 (Ollama), 3000 (Open WebUI and many agent dashboards), 5678 (n8n), 8080 (assorted), 7860 (Gradio), 1234 (LM Studio).
Step 3 — See what a stranger sees
An open port is one thing; an open port that answers is another. From that same external machine:
curl -s -m 10 http://YOUR.SERVER.IP:11434/api/tags
If that returns a JSON list of your models, you are one of the 31%. Anyone on the internet can now run inference on your hardware, read whatever context you’ve wired in, and — if you’ve connected tools — invoke them.
The equivalent for a web dashboard is simpler still: open http://YOUR.SERVER.IP:3000 in a private browser window with no session. If you get a usable interface rather than a login screen, that’s the whole finding.
Step 4 — Check whether it was found
Exposure and discovery are different problems. Services like Shodan and Censys continuously scan the internet and index what answers, so a port that’s been open for a week has very likely been catalogued. Both let you look up your own IP address to see what they hold on it, and it’s worth doing — it tells you whether to treat this as a near miss or an incident.
If your endpoint was indexed and unauthenticated, assume it was reached. Rotate any API keys the agent had access to, and check your provider billing for usage you don’t recognise — that’s what the 518 wrapped-frontier-model instances were being used for.
The fixes
Bind to loopback. The best outcome is a service that never listens publicly. For Docker, put the host address in the publish flag:
docker run -p 127.0.0.1:11434:11434 …
In docker-compose.yml:
ports:
- "127.0.0.1:11434:11434"
For services run directly, set the bind address in their own configuration rather than relying on the firewall — most accept a host argument or an environment variable.
Don’t rely on ufw in front of Docker. (Why, in full.) Given the documented incompatibility, ufw deny 11434 on a Docker-published port is a rule that reads correctly and does nothing. Either publish to loopback as above, or filter with the DOCKER-USER chain, which is the hook Docker provides for exactly this and which is evaluated for container traffic.
Use your provider’s network firewall as well. Hetzner, DigitalOcean and most others offer a firewall that sits outside the machine entirely, so Docker’s iptables manipulation can’t route around it. Two layers, one of which the host OS can’t undermine.
For remote access, use a private network rather than an open port. Putting the agent behind Tailscale is the full version of this — it closes every public port including 22, and works because an agent dials out rather than listening. If you genuinely need to reach the agent from your laptop, the answer isn’t a public port with a password bolted on — it’s a WireGuard or Tailscale network where the service stays bound to an interface the internet cannot route to. The service keeps listening on loopback or the tailnet address; nothing is published.
Then re-run steps 2 and 3. A fix you haven’t verified from outside is a belief, not a change.
What this costs you if you skip it
Three distinct exposures, in rough order of how much they hurt:
- Your compute. Strangers running inference on hardware you’re paying for. Annoying, and the cheapest of the three.
- Your API budget. If the agent holds keys to a paid model, an open endpoint is a bill with no ceiling. This is what those 518 instances were.
- Your tools and data. This is the one that matters. An agent is valuable because it’s connected to things — files, databases, email, a shell. An unauthenticated agent hands those connections to whoever finds it, and no amount of model-level guardrails substitutes for the endpoint not being reachable.
If you’re setting a server up now rather than auditing one, our guide to self-hosting OpenClaw on a VPS covers the install path, and best VPS for Ollama covers sizing. Do the loopback binding at install time and you never need this article.
How we checked this
The exposure figures are from research by the Intruder team, published May 2026: 2 million+ hosts scanned via certificate transparency logs, 5,200+ Ollama servers sent a test prompt with 31% answering, 518 instances found wrapping paid frontier models, and 90+ exposed n8n and Flowise instances. Those are their numbers, not ours — we have not repeated the scan, and re-running it is not something we’d publish.
The Docker behaviour is quoted directly from Docker’s own documentation — both the ufw incompatibility and the 0.0.0.0 publish default — rather than from community write-ups, because this specific mechanism is widely paraphrased and frequently paraphrased wrongly.
What we have not done: we haven’t tested every service’s default bind address, which changes between versions and between install methods. That’s exactly why the audit starts with ss -tulpn on your own machine rather than a table of defaults in an article — the only authoritative answer for your server is the one your server gives you.
This article has no affiliate links. Nothing here is a product recommendation.
FAQ
How do I know if my Ollama instance is public?
From a machine outside your network, run curl -s -m 10 http://YOUR.SERVER.IP:11434/api/tags. If it returns your model list, it’s public and unauthenticated. Checking with ss -tulpn on the server tells you what it’s bound to, but only the external test proves reachability.
I have ufw enabled. Am I safe?
Not if the service is published by Docker. Docker’s documentation states that container traffic is routed in the nat table before reaching the chains ufw uses, “effectively ignoring your firewall configuration.” Bind the published port to 127.0.0.1, filter via DOCKER-USER, or use a network firewall outside the host.
What’s the difference between 0.0.0.0 and 127.0.0.1?
127.0.0.1 is loopback — only processes on the same machine can connect. 0.0.0.0 means every network interface the machine has, including its public IP. In ss -tulpn output that single column is the fastest signal of whether you have a problem.
Does adding a password fix it?
It’s much better than nothing, but an authenticated service on a public port is still a service being probed continuously by automated scanners. Prefer not publishing the port at all and reaching it over a private network; use authentication as a second layer rather than the only one.
How would I know if someone already used my instance?
Check whether Shodan or Censys have your IP indexed, look for usage you can’t account for in your model provider’s billing, and review the agent’s own logs for requests you didn’t make. If the endpoint was open and unauthenticated, treat any connected credentials as compromised and rotate them.
Which ports should I be checking?
11434 for Ollama, 3000 for Open WebUI and many agent dashboards, 5678 for n8n, 7860 for Gradio, 1234 for LM Studio, and 8080 for a long tail of things. Rather than trusting a list, read what’s actually listening with ss -tulpn and check every entry bound to 0.0.0.0.
Is it legal to port scan my own server?
Scanning infrastructure you own or administer is routine administration. Scanning hosts you don’t control is not, regardless of intent — keep every step in this article pointed at your own IP address.