← All campaigns

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.

MITRE ATT&CK techniques T1552.001T1078.004T1496

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:

  1. Spin up servers. Six attempts to launch cloud servers (RunInstances) — the quickest way to turn a stolen key into compute. All six refused.
  2. 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.
  3. Reach the AI. Twenty-three attempts to call Amazon Bedrock — AWS’s hosted-AI service, the actual prize (InvokeModel). Every one denied.
  4. Grant themselves access. Blocked from the models, they made three attempts to rewrite their own account permissions (PutUserPolicy) to unlock them. Denied.
  5. 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 /script or /scriptText whose body contains System.getenv() filtered for ANTHROPIC / AWS / SECRET, or that read credentials.xml or ~/.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 denied InvokeModel calls; 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 block 83.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[.]54
  • 83.171.227[.]0/24
  • AS41745

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.

Sigma: Jenkins Credential Hunt
jenkins_groovy_cloud_cred_hunt.yml
DetectsJenkins Script Console Groovy requests hunting AWS/Anthropic credentials (inbound)
DeployWeb server / reverse proxy logs in front of Jenkins
When it firesWhen a /script or /scriptText request body enumerates env vars for ANTHROPIC/AWS/SECRET or reads credentials.xml
Sigma: Provider-Key Sweep
provider_key_sweep_exec.yml
DetectsA process searching for Anthropic/OpenAI/OpenRouter API key prefixes (process execution)
DeployEDR / process-creation telemetry
When it firesWhen a grep-family process or inline env search matches all three provider key prefixes together
Sigma: Stolen-Key Cloud Abuse
stolen_key_bedrock_worked_cloudtrail.yml
DetectsA stolen AWS key being worked toward Bedrock access (CloudTrail)
DeployAWS CloudTrail
When it firesOn a GetCallerIdentity-then-InvokeModel pattern, a PutUserPolicy/Bedrock entitlement call, or RunInstances abuse from an unusual principal
IOC CSV
docker-cloudkey-llm-harvest-iocs.csv
DetectsAtomic indicators — source address, network prefix, ASN

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.

Browse by
JenkinsDocker APILangflowglobaljenkins-groovy-console:env-enum+credential-file-readdocker-api-exec:container-env-inspect+key-exfilstolen-key-decision-tree:identity-check-then-model-invoke-then-self-grant-then-retryprovider-key-sweep:multi-prefix-grep-env-and-filesystemLLM/cloud credential theft for free AI compute access
llmjackingdockercloud-credential-theftbedrock
Subscribe for new analysis Compare with another campaign