Stolen AI keys can cost $100,000 a day. Three checks to run on your server
If your website or app talks to an AI service, there's a key on a server somewhere that lets it run up a bill in your name. Criminals have noticed. Google's threat team says stolen keys have cost some organisations over $100,000 in a single day.
The fix is mostly boring housekeeping: three checks on your server, and one setting that limits the damage.
What happened
On 2 November, Google's threat intelligence team and Mandiant published a report on what they call LLMJacking. Criminals get hold of someone's access to an AI model, use it, and in some cases resell it. The Register covered it here.
Google saw fraudulent charges of over $100,000 in a day in individual incidents, and cumulative charges at some organisations reaching $1 million before access was cut off. It says this can generate "large spikes in fraudulent cloud charges in a matter of hours."
How they get in is less exotic. Stolen cloud credentials are the main route. Keys left in public code on GitHub are another. And in one example, an attacker found a self-hosted Ollama server open to the internet and loaded its own models onto it.
The team at Dev Partners has written up the business side of this, including keys in code and Git history. I'm going to stick to the server.
Does it affect you?
Probably, if any of these are true:
- Your website, shop or app uses ChatGPT, Claude, Gemini or similar behind the scenes.
- Someone built you an app with AI tools and you've never looked at where the keys live.
- You've been trying out Ollama or another local AI tool on a server.
If none of that applies, this one can wait.
Check 1: is Ollama open to the internet?
Ollama's own docs say it listens on 127.0.0.1, port 11434, by default. That's only reachable from the server itself, which is what you want. The trouble starts when someone changes it to 0.0.0.0 to get it working from another machine.
On the server, run:
sudo ss -tlnp | grep 11434127.0.0.1:11434 is fine. 0.0.0.0:11434 or *:11434 means it's listening on every address.
Docker is the one that catches people out. Ollama's Docker instructions use -p 11434:11434, and Docker's own docs say that publishes the port on all host addresses. They describe published ports as "insecure by default". Worse, Docker says that traffic to published ports skips ufw rules entirely. So your firewall can say "blocked" and still let it through.
The fix is to publish it to the server only:
-p 127.0.0.1:11434:11434Then reach it from elsewhere over a VPN such as Tailscale, which is how I said I'd run it when I wrote about building a local AI server.
Check 2: can anyone download your keys?
Most apps keep their keys in a file called .env. That's fine, as long as the web server never hands it out. Try this from your own computer, with your own domain in place of example.co.uk:
curl -s -o /dev/null -w '%{http_code}\n' https://example.co.uk/.env
curl -s -o /dev/null -w '%{http_code}\n' https://example.co.uk/.git/configYou want 404 or 403 back. A 200 means the file may be readable by anyone, so open it in a browser and look. If it's your keys or Git settings, block it in the web server config, then go straight to check 3.
The .git one matters because a copy of the Git folder can contain old versions of every file, including keys you thought you'd deleted.
Check 3: rotate anything you're unsure about
If a key has ever been in a public repository, a .env file anyone could download, a chat message or a shared document, assume it's gone. Create a new key in your AI provider's dashboard, put it on the server, restart the app, then delete the old one. In that order, or the app stops working in between.
While you're in there, delete keys nobody recognises. Google recommends restricting keys by model, by environment and by usage limit, so a stolen test key can't call the most expensive model.
The setting that limits the damage
Set a spending limit with your AI provider, and find out whether it's a hard stop or just an email.
They aren't all the same. Anthropic's docs say you can set your own monthly spend limit on the Billing page, and requests are refused once you reach it. Google Cloud's budget docs say an alerts-only budget "doesn't automatically cap" spending. It tells you. It doesn't stop anything.
An alert is still worth having. Just don't treat it as a lock.
What to do this week
- Run the
sscommand on any server with AI tools on it. - Run the two
curlchecks against every site you look after. - Rotate any key you're not sure about.
- Set a spending limit at each AI provider, and an alert below it.
If someone else built your app
If your app was built by a developer who's moved on, or knocked together with AI tools, you may not know where the keys are or how many there are. The team at Dev Partners does a fixed-price code audit that answers that, along with the rest of what's in there. For the server side, that's what my health check is for.
Liked that? Get the next one by email
When a security flaw lands that could affect your server, I'll email you what it means and what to do. Plus the odd opinion piece. Not often, no spam.