One Operator, Every LLM Key They Could Reach
For three months, one attacker chased a single goal — free AI compute, taken from the machines they broke into. Wherever they landed, they went after two things: cloud login keys they could point at a provider's hosted AI models, and the raw API keys that developers leave sitting in configuration files.
Summary
For three months, one attacker chased a single goal — free AI compute, taken from the machines they broke into. Wherever they landed, they went after two things: cloud login keys they could point at a provider’s hosted AI models, and the raw API keys that developers leave sitting in configuration files.
We watched the whole thing happen on decoy machines we run. Most reports can’t show what an attacker does with a stolen cloud key after they think they have a working one — we can, because the key we planted was real enough to log in with. The same address that lifted that key off one of our machines was firing it at real, live cloud APIs minutes later.
Stealing cloud keys to run someone else’s AI models on their bill has a name — LLMjacking — and it’s been written about for a couple of years. What those write-ups don’t have is a single operator followed from break-in to abuse. We do. We logged every move they made with the stolen key, in order, as each one came back refused, and we captured — word for word — the command they ran to sweep a machine for Anthropic, OpenAI, and OpenRouter keys.
1. One address, hunting AI credentials on every machine they got into
A single address — 83.171.227[.]54 — touched eleven of
our decoy products over roughly three months (July to September 2026,
368 visits in all). They got deep into three of them, and on all three
they did the same thing: went looking for AI and cloud credentials. Here
is what happened on each.
Jenkins — late August
Jenkins is a build server: software teams use it to compile and ship code. It ships with a built-in web console that runs small scripts (in a language called Groovy) directly on the server — a feature meant for administrators. If that console is reachable from the internet, anyone can run code on the box.
The attacker used it to dump the server’s environment variables,
filtering for anything named AWS, ANTHROPIC,
or SECRET, and then to read the files where cloud keys and
Jenkins’ own saved passwords live. Captured from the console, recorded
as evidence:
println System.getenv().findAll{k,v-> k.contains("AWS")||k.contains("ANTHROPIC")||k.contains("SECRET")}
println(["bash","-c","cat /var/lib/jenkins/credentials.xml 2>/dev/null | head -50"].execute().text)
Docker — mid-September, and what they did with the key
Docker is the software that runs “containers” — self-contained packages of an application. It has a remote-control API, and when that API is left open to the internet (on its network port, 2375) anyone can list, inspect, and run containers on the machine with no password.
The attacker inspected every container on the box to read its settings, which is exactly where applications keep their cloud keys. We had planted an Amazon Web Services login key there for them to find. They took it straight to AWS’s real APIs.
Because the key was one of ours, we have the complete record of what they tried to do with it — pulled from AWS’s own audit log, every step refused:
- Spin up servers. Six attempts to launch cloud
servers (
RunInstances) — the quickest way to turn a stolen key into compute. All six refused. - Confirm the key is live. Fifteen identity checks
(
GetCallerIdentity). This call answers for any valid key, so it tells an attacker the key still works. - Reach the AI. Twenty-three attempts to call Amazon
Bedrock — AWS’s hosted-AI service, the actual prize
(
InvokeModel). Every one denied. - Grant themselves access. Blocked from the models,
they made three attempts to rewrite their own account permissions
(
PutUserPolicy) to unlock them. Denied. - Try the AI once more. One final model call the moment the permission grab failed. Denied.
Docker and Langflow — late September
A week later they came back to the Docker machine and ran a command
inside the containers that searched the whole filesystem for
provider API keys, matching them by the exact prefixes each vendor uses.
Captured from the request, recorded as evidence (the search patterns
match Anthropic sk-ant-api…, OpenAI sk-proj…,
and OpenRouter sk-or-v1… keys):
env 2>/dev/null | grep -iE 'openai|anthropic|claude|api_key|token|secret'
grep -rhoE 'sk-ant-api[0-9]{2}-[A-Za-z0-9_-]{20,}|sk-proj-[A-Za-z0-9_-]{40,}|sk-or-v1-[a-f0-9]{64}' \
/app /code /srv /opt /root /home /etc /data /var/www /usr/src
find / -xdev -name '.env*' -not -path '*/node_modules/*' | xargs grep -hiE 'sk-|ANTHROPIC|OPENAI'
The next day the same key-search turned up on a third product — a decoy Langflow server (Langflow is an open-source tool for building AI workflows). The attacker reached it through a code-checking feature in Langflow, used it to run Python that dumped the environment, and ran the same kind of sweep for Anthropic, OpenAI, OpenRouter, and Google keys. The same hunt, carried from one product to the next.
2. What it means
This is deliberate, targeted credential theft, not random mining. The attacker worked their one stolen cloud key through a clear order of payoffs: first free servers, then access to the hosted AI models, and when that was refused, an attempt to grant themselves the permissions to get in. A week later they went after raw provider keys directly.
The permission grab is the tell that a person is at the keyboard, not a script. Refused on the model call, they tried to rewrite their own account permissions and then retried the model call once that failed — a decision made in the moment. They reached for a crude, all-purpose permission change rather than the specific Bedrock settings that published research describes, which marks them as a capable operator working by hand rather than a polished toolkit.
Our confidence: high that the goal is LLM-credential theft — their own commands name the providers; high that they gained no access to the cloud account — every action against the real key was refused; medium on whether this is one person or a small crew sharing tools.
3. Why this matters to a defender
The root cause is an old one: a device left reachable from the open internet with no lock on the door. Every machine in this story — the build server, the Docker host, the AI-workflow tool — was answering commands from anyone who could find it. That is a mistake personal projects and smaller organizations make all the time, often without realizing the thing is exposed at all.
And the damage isn’t a wiped server. This attacker doesn’t want to break your machine — a wiped box just gets rebuilt with fresh keys. They would rather leave everything running and quietly run up a bill on your cloud account, or walk off with a model key that keeps working long after the machine itself is cleaned up.
Who is exposed: anyone running a Docker API open to the internet (port 2375) or a Jenkins server with its Script Console reachable, and any team whose build servers or containers keep cloud keys or AI provider keys in environment variables or configuration files. This is not a narrow target — routine internet-wide scans find thousands of open Docker 2375 machines at any given time.
4. What to hunt for
- The provider-key sweep. A process reading
environment variables or files and matching all three vendor prefixes
together —
sk-ant-api,sk-proj-,sk-or-v1-— is high-confidence malicious. A single search naming all three is not something a normal program does. - Jenkins Script Console. Requests to
/scriptor/scriptTextwhose body containsSystem.getenv()filtered forANTHROPIC/AWS/SECRET, or that readcredentials.xmlor~/.aws/credentials. - Docker API. An unauthenticated
GET /containers/json(list), followed by per-container inspects, followed by/containers/{id}/exec— enumeration running straight into command execution. - On the cloud side. The sequence that means a stolen
key is being worked rather than used normally: an identity
check (
GetCallerIdentity) immediately followed by a model call (InvokeModel); any attempt to rewrite account permissions (PutUserPolicy) or change Bedrock access from an account that has never done so before; bursts of deniedInvokeModelcalls; and server launches (RunInstances) from an account that doesn’t normally make them. - The address and its network. Source
83.171.227[.]54, in the block83.171.227[.]0/24, which belongs to a network provider identified as AS41745 (FORTIS-AS) — the company that announces this range of addresses to the internet. This is abuse-tolerant hosting: the network sits on public bad-reputation lists, and GreyNoise — a service that tracks internet-wide scanning traffic — flags its ranges as malicious, so the single address is disposable. Block and watch at the network-block level, not just this one IP. The network is registered in Europe but operated from Russia, which is why the address geolocates inconsistently — trust the network, not the country.
Detection content ships with this brief:
docker-cloudkey-llm-harvest-iocs.csv, plus Sigma detection
rules for the provider-key sweep, the Jenkins credential hunt, and the
cloud-side key-abuse sequence. Every figure in this brief is pinned in
docker-cloudkey-llm-harvest-evidence.json.
Indicators of Compromise
83.171.227[.]5483.171.227[.]0/24AS41745
Detection Rules & IOCs
Three rules at three different points in the chain: a build-server credential hunt, an in-container key sweep, and a cloud-side decision-tree over CloudTrail. Coverage holds whether the attacker reaches a Jenkins console, a Docker API, or a stolen AWS key itself.
jenkins_groovy_cloud_cred_hunt.yml
provider_key_sweep_exec.yml
stolen_key_bedrock_worked_cloudtrail.yml
docker-cloudkey-llm-harvest-iocs.csv
In plain terms
- A cloud key whose identity is checked (GetCallerIdentity) and then immediately used to call a hosted AI model (InvokeModel) is being actively worked, not just validated.
- An account that has never touched AI services suddenly tries to grant itself Bedrock access, or rewrite its own permissions, right after an AI model call gets denied.
- A single process searching for Anthropic, OpenAI, and OpenRouter key prefixes together in one sweep is not something a legitimate program does.
Frequently asked
What is One Operator, Every LLM Key They Could Reach?
For three months, one attacker chased a single goal — free AI compute, taken from the machines they broke into. Wherever they landed, they went after two things: cloud login keys they could point at a provider's hosted AI models, and the raw API keys that developers leave sitting in configuration files.
What are the indicators of compromise (IOCs) for One Operator, Every LLM Key They Could Reach?
Key indicators include 83.171.227[.]54, 83.171.227[.]0/24, AS41745. The full list and a downloadable IOC CSV are in the Detection Rules & IOCs section.
How do I detect One Operator, Every LLM Key They Could Reach?
One Operator, Every LLM Key They Could Reach can be detected with Sigma: Jenkins Credential Hunt, Sigma: Provider-Key Sweep, Sigma: Stolen-Key Cloud Abuse, IOC CSV — all downloadable on this page. Three rules at three different points in the chain: a build-server credential hunt, an in-container key sweep, and a cloud-side decision-tree over CloudTrail. Coverage holds whether the attacker reaches a Jenkins console, a Docker API, or a stolen AWS key itself.
What MITRE ATT&CK techniques does One Operator, Every LLM Key They Could Reach use?
One Operator, Every LLM Key They Could Reach maps to T1552.001, T1078.004, T1496.