Mastodon Skip to content
ai.rud.is
Go back

Somebody Is Hunting For Your AI API Keys With A Fake GrokBot User-Agent

hrbrmstrMD

As folks who follow me on Mastodon (or the various blogs and newsletters) know, I – along with Glenn Thorpe – run a small fleet of honeypot sensors. We recently reconfigured them to test some new deception tech and run deliberate deception campaigns, rather than just capturing background internet noise, which is increasingly of little value. For this configuration, we seeded /.env files that look like they hold real cloud credentials. The credentials are canary tokens. When a thief takes one and uses it in AWS, the token fires an alert via Tracebit Community. The fleet tells me who (IP address) took it and what else they did while they were there.

On August 29, one of the fake workstations handed seventeen sets of AWS credentials to a machine in Tokyo. Within ten seconds, those credentials showed up in Amazon Bedrock, pointed at the cheapest generative model Amazon sells. The same playbook ran again from a different Google Cloud IP on August 30. Then twice on September 1 and 2. On September 3rd, a sixth Google Cloud machine stole a credential and tried the same Bedrock call – from a machine that never touched a sensor from the fleet.

This post is about that operator: what they steal, how they disguise themselves, what they do with the take, and why their target choice tells you something about where attacker economics are heading.


The operator runs one script. Six source IPs over six days, all Google Compute Engine – Tokyo, Singapore, Brussels twice, Washington twice, then North Charleston. Each run follows the same shape: probe the target with a canary detector path that names the campaign (/__aws_leak_probe_<hex>__), rotate through 43 to 473 forged user-agents while walking a credential wordlist (/.env, /.env.openai, /.env.anthropic, /.aws/credentials, /openai.json, /.claude.json, /.cursor/mcp.json, /.config/anthropic/credentials/default.json, /.aider.conf.yml), take whatever the deception sensor serves, and leave.

The user-agent list forges GPTBot, ClaudeBot, Claude-User, PerplexityBot, Perplexity-User, OAI-SearchBot, GrokBot, Applebot, Amazonbot, Google-Extended, meta-externalagent, ChatGPT-User, and more. The rotation mixes AI crawler brands with stale desktop and mobile browser strings – the goal being to make each request look like it came from a different kind of visitor, so rate limits and per-UA rules see noise instead of a scan.

GrokBot appears in every run, on paths like /home/runner/.aws/credentials and /azure.json – credential paths using x.ai’s crawler identity. The real GrokBot has a published IP range and a verification scheme, which makes a counterfeit pretty easy to detect if you bother to check. The fact that this operator doesn’t expect you to bother is, itself, the tell.

The wordlist makes clear that the operator knows exactly where AI credentials live on a developer machine: Claude Desktop config, Cursor MCP config, Aider config, OpenAI and Anthropic credential files. AI provider keys are primary loot here, on equal footing with AWS keys.

Tracebit fired alerts when the stolen AWS temporary credentials were used, and two distinct patterns emerged.

Pattern one, August 29: Go-http-client/1.1 from the same Tokyo VM that did the stealing, nineteen bedrock:Converse calls against amazon.nova-micro-v1:0, ten seconds after mint. All denied.

Pattern two, September 3: axios/1.18.1 from AWS EC2 runners – different IPs than the thieves – hammering ses:GetSendQuota and sns:GetSMSAttributes, thirty-four calls in one second. That was a Bucklog campaign, a separate operator. One sts:GetCallerIdentity succeeded per burst (the trick that convinces them the key is legit). Everything else denied.

Pattern one returned on September 3 at 07:50:56 UTC. A machine in Brussels – 207.175.90.192, Google Cloud, never seen by the honeypot fleet – took a canary credential from a path it reached with the forged GrokBot user-agent. Ten seconds later, one bedrock:Converse call against nova-micro from that same IP. Denied.

Ten seconds, twice, on different days, from different continents. Someone has this bot work down to a science.


amazon.nova-micro is the smallest, cheapest model in the Nova family. Nobody picks it for capability. You pick it when you want the highest call volume per dollar – or per stolen credential.

Three likely uses for these AI API keys: resale inventory (stolen provider keys get bulk-listed on Telegram channels and grey-market sites; a Bedrock call is a validity test before listing), direct use (someone wants LLM capacity they don’t want to pay for, and nova-micro is cheap enough to matter at scale), or recon (a successful model call would reveal the credential’s scope and point the attacker at whatever else the role permits). All three readings end the same way for the defender: an AI API key in a plaintext file is now worth stealing at scale, by tooling that checks its value within seconds of taking it.


Every denial in this story carries the same signature:

User: arn:aws:sts::...:assumed-role/legacyOwnerAccess/...
is not authorized to perform: bedrock:InvokeModel on resource:
arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-micro-v1:0
with an explicit deny in an identity-based policy:
arn:aws:iam::...:policy/legacyOwnerAccess-DenyAll

The canary role carries an identity-based policy named legacyOwnerAccess-DenyAll that denies everything. Not “deny unless trusted” – deny. The role exists to be stolen. Its only value is the alert it generates when someone tries to use it, and the audit trail of what they tried.

The cost of that control is one policy document. Fifty-two credential mints, three separate theft waves, twenty-five denied AWS calls across two operators, and the total “damage” is a detection log. The attacker gets nothing; you get a structured, timestamped, attributable record of exactly what they tried vs. a giant AWS bill.


The forged user-agent list is the operational takeaway. A scan rotating GPTBot, ClaudeBot, PerplexityBot, and GrokBot strings is built to defeat two specific defenses: user-agent allowlists, and the human habit of treating known crawler brands as safe.

I’d assert that ~3 defenses hold up against this kit.

Check crawler identity by — at a minimum — reverse DNS, and absolutely not by user-agent string. Every major AI operator publishes guidance for this – OpenAI, Anthropic, Perplexity, and x.ai all document IP-range or PTR checks. A request claiming GrokBot identity from googleusercontent.com fails that check in one lookup.

Never serve .env, credential, or config files over plain HTTP from an internet-reachable host. This kit walked forty-plus /.env variants against three deception nodes in six days and collected fifty-two credential sets because the honeypots were configured to hand them over. A real host shouldn’t.

Treat any AI API key that ever touched a disk reachable by a web server as potentially compromised. The wordlist covers Claude Desktop config, Cursor MCP config, Aider config, and OpenAI/Anthropic credential JSON in six locations each. If your keys live where that wordlist looks, someone may have already read them. Rotate on a schedule, and make them short-lived to begin with.


The gap between “file read” and “cloud API call” is now shorter than most detection pipelines. If your .env file leaks at 09:00:00 and your key rotation job runs nightly, the attacker held a working credential for most of a day. In this dataset, the attacker’s use happened before the next calendar minute.

Canary credentials flip that math. The thief can’t tell a canary key from a real one, so their speed becomes your signal. Ten seconds from mint to first use means the alert arrives before the attacker has finished their run – and that’s a detection posture worth building before the operator switches from nova-micro probes to something that actually succeeds.

The Brussels machine from September 3 never appeared in honeypot fleet logs; the fleet’s last event predates the theft by twenty minutes, so the full journey for that run is still unobserved (we’ll be watching closely for a return visit). I also can’t tell whether the six GCP VMs belong to one person or several sharing tooling. The fifty-two mints and denied Bedrock attempts could be failed infrastructure tests before a pivot, or they could be the full extent of the operation.

If you haven’t poked at your internet-facing deployments lately, make sure nobody on the team did an errant git push with an .env file that didn’t make the .gitignore cut.



Previous Post
What 100 Cybersecurity Vendors Tell AI Agents: An llms.txt Census
Next Post
Bulletproof Hosting Watch: Week of 2026-08-31