AI API Key Security 2026: 9 Platform Breaches
Nine AI developer platforms disclosed breaches in October 2026. Stolen keys drove 2.5 million AWS Bedrock calls. Here is the IAM fix that stops it.
What happened in October 2026
On October 30, 2026, Wiz published a consolidated analysis of what it called "Black October" for AI Developer Platforms: at least nine AI developer platforms disclosed security incidents over the course of that single month, and the researchers found that the incidents share a common shape even though no single vulnerability links them.
The platforms and dates, as listed by Wiz:
| Platform | Disclosure date | Root cause as reported |
|---|---|---|
| Fireworks AI | October 6 | Credential access |
| Andromeda | October 9 | Called an "industry-wide attack" |
| Zeabur | October 14 | Plaintext long-lived admin credentials |
| Lightning AI | October 15 | Credential access; previously hit by the Mini-Shai Hulud supply chain campaign |
| OpenCode | October 16 and 17 | A "legacy system"; reported an agent swarm attack |
| Railway | October 20 | "Privilege escalation in our build infrastructure" |
| Warp | October 23 | A third-party vendor dependency |
| CommandCode | October 28 | Attributed to an attempt at distillation |
| Northflank | October 30 | Not yet published |
Three platforms (Fireworks, OpenCode, and Warp) reported indications of an agent swarm attack, and OpenCode and CommandCode explicitly attributed their incidents to an attempt at model distillation. The pattern across all public reports, in Wiz's words, is targeted exploitation that explicitly hunts stored environment variables, with the focus on those granting AI access. If you keep an LLM provider key in an environment variable on a managed platform, this is the attack that was looking for it.
There is no single vulnerability, and that is the uncomfortable part
Most breach roundups end with a patch and a version number. This one does not. Fireworks, Zeabur, and Lightning AI all point at credential access. Railway points at privilege escalation in its build infrastructure. Warp points at a third-party dependency. OpenCode points at a legacy system. Lightning AI had already been hit once by the Mini-Shai Hulud supply chain campaign before this.
The unifying element is not a vulnerability in an AI platform. It is the combination of long-lived credentials stored in a reachable place plus an attacker with a machine that can try thousands of them per minute. Wiz points at two forces driving that: agentic attacks, which let an attacker compromise victims faster, and the rise of LLMJacking, where stolen API access is resold through what the researchers call LLM brokers, giving the theft a monetisation path that did not exist a few years ago. Demand for model outputs to distill also pushes in the same direction.
What the attackers did after the breach
This is the part that matters most for API developers, because the breach is the boring half. Wiz observed two enterprise AWS cases where credentials compromised at a vendor platform were then used against the customer's own AWS accounts, and the usage patterns were remarkably consistent.
In both cases the first unauthorized activity happened within 30 minutes of the reported credential access. It was a single InvokeModel call from a residential IP address, in a one-minute sweep that tested the stolen key against multiple organizations. The call asked for one Claude model, failed, and fell back to another that worked. Over the following days, both keys saw only a trickle of traffic, 14 to 120 calls a day from the same small client, with the two keys running in lockstep about a minute apart. That is a validation job: an actor checking the keys were still alive.
Then the floods. In Case A, four days after validation, a rotating proxy pool ran a catalog probe across dozens of addresses, sending one call per model across vendors including Amazon Nova, DeepSeek, GLM, Kimi, Grok, and GPT-6 Astra. A few hours later a boto3 script enumerated Bedrock and EC2 quotas, and within the next half hour a second host mapped quotas and model availability across Regions with more than a thousand calls in under a minute. Over roughly thirty hours the actor made about 800,000 Bedrock calls, around 90 percent of which succeeded.
Case B went the other way. The key was already restricted to a specific geography, and the calls failed for two days until a checker on a shared VPN exit identified the working model IDs, at which point the floodgates opened. That single address made about 1.7 million Bedrock calls over thirteen hours, with over a million successful. Wiz's estimate: at list price, these two cases alone likely ran up over $100,000 in usage.
The cross-Region detail that decides whether you get hammered
Here is the technical heart of the incident, and it is the part most developers do not know exists. Amazon Bedrock offers two kinds of cross-Region inference profile. A geographic profile is prefixed by a geography, such as us., eu., apac., or in., and keeps processing inside that geography. A global profile is prefixed by global. and routes requests to any supported commercial Region worldwide. AWS documents that Global profiles save approximately 10 percent on input and output token pricing, and that the price is always calculated from the source Region regardless of where the request actually runs.
In Case A the stolen key's policy allowed global.* profiles, so the attacker routed every call through them. Because global routing spreads load across Regions, only about 6 percent of the 800,000 calls were throttled. In Case B the key was limited to us.* profiles; the attacker's global attempts failed, and once it found the working regional model IDs, the flood was still mostly throttled because the traffic ran into the account's regional quotas. Nearly all of that excess was throttled rather than served.
Two operational consequences follow. First, a global profile multiplies the blast radius of a stolen key, because it converts one regional quota into a worldwide pool. Second, the quota numbers you monitor are not the quota the attacker burns. If you are watching regional token-per-minute limits, a global-profile key is invisible to that monitor.
AWS also documents a detail that makes the IAM fix non-obvious: enabling Global cross-Region inference requires three separate resource ARNs to be allowed, not one. The regional inference profile ARN, the regional foundation model ARN, and the global foundation model ARN that has no Region and no account in it. The global ARN's emptiness is intentional. A policy that allows only the first two silently fails to enable global routing, and a policy that allows all three without a deny opens it.
What a platform breach actually exposes: the Zeabur numbers
Zeabur published the most complete write-up of the month and is shutting down as a result, with shared cluster services pausing from December 1, 2026 and all dedicated servers and shared clusters stopping by December 31. Its own October 19 preliminary report gives the clearest picture of what a hosting platform breach means for the API keys sitting inside it.
On October 14 and 15 the attacker used leaked internal credentials to reach the shared cluster, some dedicated servers, and Zeabur internal systems, eventually reading the platform database. The shared cluster's admin interface was open to the public internet and the admin tokens had no expiry. The attacker ran commands inside user database containers across 865 database services, reading n8n instances at scale and walking through PostgreSQL databases table by table, then read about 53 production secrets from the secrets management service.
| Data read | Volume | Certainty (per Zeabur) |
|---|---|---|
| Service environment variables (names and values) | 3,218,965 records | Confirmed |
| Account records (email, username, phone) | 321,810 accounts | Confirmed |
| zSend API keys stored in plaintext | 566 keys, revoked | Confirmed |
| Platform access tokens | 11,536 tokens, stored only as hashes, all revoked | Confirmed |
| Environment variables and secrets of all shared-cluster services | 9 Regions | Partly confirmed, the rest treated as leaked |
| Contents of user databases | 865 database services | Assessed |
| Data on GCP dedicated servers | 101 servers, 92 users | Sign-ins confirmed |
Two details in that table deserve emphasis. The access tokens were stored only as hashes and could not be reversed, while the zSend API keys were stored in plaintext, which is the same design mistake repeated at two different layers. And the guidance is stronger than a routine rotation: because the August credential rotation did not cover the credentials used this time, Zeabur tells users to replace every password and key stored on the platform even if they already replaced them after the earlier incident. One mitigation did work, and it is worth copying. Projects that had moved their environment variables to their own dedicated server after August were outside the scope of the platform database read.
The resale market is the reason this keeps happening
Wiz identified two operations that were actively trading on stolen keys. One operator, centred on a single IP address that Zeabur also named in its own disclosure, runs a site advertising discounted access to frontier models with payment accepted in USDT. The infrastructure behind it goes back to 2025 and has hosted a series of LLM resale pages, including a chat account pool management site in March 2026 and, four days before Zeabur's timeline identified the IP address, an autonomous penetration testing console. A second hub at a different address performs permission checks against stolen keys across multiple organizations.
One detail in that second operation is worth reading twice, because it explains the economics. Its domain was snapshotted hosting a page titled "Distillation behaviour detection" that scored users as high risk, watch, or normal. The researchers read that as the operator trying to keep their accounts away from traffic that would look like distillation, because distillation is what gets accounts suspended. That is a resale operation with a compliance function, not a script kiddie with a leaked key.
Wiz is explicit about the limit of the evidence: it has no evidence linking the resale infrastructure directly to the Black October attacks. What it can show is that these operators had access to the stolen keys and were testing them, which is evidence of an active market for the credentials.
Five controls that actually change the outcome
The defensive advice is not complicated, and all five items are things you can do this week without buying a new security product.
One. Scope every key to a single model and a single Region. An IAM role whose policy allows bedrock:InvokeModel against one specific inference profile ARN and one specific foundation model ARN is useless to an attacker, because the catalog probe across a dozen vendors fails immediately. AWS's own note that you can replace the InvokeModel statement's Resource with specific model and inference profile ARNs is the entire mechanism.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOneScopedProfile",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0"
]
},
{
"Sid": "DenyGlobalCrossRegionRouting",
"Effect": "Deny",
"Action": [
"bedrock:InvokeModel*",
"bedrock:Converse*",
"bedrock:ConverseStream*"
],
"Resource": "*",
"Condition": {
"StringEquals": { "aws:RequestedRegion": "unspecified" }
}
}
]
}
The deny block is the part people get wrong. AWS documents that Global cross-Region inference evaluates the Region-agnostic global foundation model resource with aws:RequestedRegion set to unspecified rather than the actual destination Region, so a conventional deny on a concrete Region name such as us-west-2 does not target it at all. If your organization blocks unused Regions with a service control policy, Global routing also requires you to allow unspecified there, or the request is denied by policy before it reaches the model.
Two. Put a hard spend cap on every key. The Wiz case studies show why: roughly 800,000 calls succeeded in one case and over a million in another, and the usage profile is a reseller running many end users behind one credential. A per-key budget with automatic cutoff converts an unbounded loss into a bounded one. A gateway gives you that plus a request log you can actually audit, which is why Portkey is a reasonable place to put per-key virtual keys and spend limits if you do not already run one, rather than bolting spend control onto every provider separately.
Three. Watch for the catalog probe, not just for a spike. The first malicious act in both Wiz cases was a one-minute sweep that tried one call per model across a dozen vendors. A normal workload does not look like that. The following script queries CloudTrail for Bedrock events, flags the IP addresses Wiz published as credential checkers, and flags any source address that made a large number of calls across many distinct models, which is the catalog probe signature.
import boto3
from collections import defaultdict
from datetime import datetime, timedelta, timezone
# The IPs Wiz published as testing stolen keys. Confirm these against your own logs.
WIZ_IOC = {
"23.106.46.239", # resale hub, also named by Zeabur
"38.246.114.118", # permission checks across several stolen keys
"104.243.32.50", # permission checks across several stolen keys
"31.57.201.201", # identified using multiple stolen keys
}
client = boto3.client("cloudtrail")
def bedrock_events(days=14):
start = datetime.now(timezone.utc) - timedelta(days=days)
token = None
while True:
kwargs = dict(
LookupAttributes=[{
"AttributeKey": "EventSource",
"AttributeValue": "bedrock.amazonaws.com",
}],
StartTime=start,
EndTime=datetime.now(timezone.utc),
MaxResults=50,
)
if token:
kwargs["NextToken"] = token
response = client.lookup_events(**kwargs)
for event in response.get("Events", []):
yield event
token = response.get("NextToken")
if not token:
break
by_ip = defaultdict(lambda: {"calls": 0, "models": set()})
for event in bedrock_events():
ip = event.get("sourceIPAddress")
if not ip:
continue
by_ip[ip]["calls"] += 1
for resource in event.get("resources") or []:
by_ip[ip]["models"].add(resource.get("ARN", "").split("/")[-1])
for ip, agg in sorted(by_ip.items(), key=lambda kv: -kv[1]["calls"]):
if ip in WIZ_IOC:
print(f"[IOC] {ip} made {agg['calls']} Bedrock calls")
elif agg["calls"] > 200 and len(agg["models"]) > 5:
print(f"[CATALOG PROBE] {ip}: {agg['calls']} calls across {len(agg['models'])} models")
Four. Rotate keys on a schedule and on every incident, not once. Zeabur's own case shows the trap: a rotation that misses one credential class, or misses the credentials created after the rotation, leaves the door open. Automation is the only version of this that survives a platform breach you did not know about.
Five. Move the highest-value keys off shared hosting entirely. The one Zeabur mitigation that demonstrably worked was moving environment variables off the platform into a dedicated server the customer controls. If a key can reach a frontier model at $5 to $25 per million output tokens, that key belongs in a secrets manager you control, not in a variable on a shared cluster.
What this article does not cover
Several limits are worth stating plainly. Most of the platform root causes are still preliminary, and Northflank had not published at the time of writing, so the list may grow. Wiz cannot link the resale sites to the campaign. The two enterprise AWS cases are examples, not a complete count of affected customers, so the total cost is unknown and higher than the reported $100,000. And nothing here establishes that any particular AI model provider was compromised: the vulnerabilities were in hosting and deployment platforms, and the API keys were the payload, not the flaw.
Verdict
The honest read on Black October is that this is not an AI-specific crisis. It is the ordinary credential theft problem, accelerated by a new incentive: model access has a clean resale market, so a stolen key now has a price. That price funds the automation that makes these campaigns cheap to run at scale.
For API developers the actions are unglamorous and mostly already known. Scope keys to one model and one Region. Deny global cross-Region routing explicitly, because the deny has to match the string unspecified. Cap spend per key. Watch for a single source address calling many different models. Rotate on a schedule. And move the keys that can actually hurt you off shared infrastructure.
The one genuinely new piece of guidance is the cross-Region detail. A restricted key is only as restricted as the inference profiles its policy allows, and a global profile turns a regional quota into a worldwide one that is 90 percent servable. If you take one thing from this, take that one.
Frequently asked questions
Which AI developer platforms were breached in October 2026? At least nine: Fireworks AI, Andromeda, Zeabur, Lightning AI, OpenCode, Railway, Warp, CommandCode, and Northflank. Wiz published the consolidated analysis on October 30, 2026.
What did the attackers steal? Environment variables granting AI access, not model weights. Every public report describes targeted hunting of stored environment variables, and Zeabur confirmed that 3,218,965 environment variable records were read from its platform database.
How much did the stolen keys cost? Over $100,000 at list price across the two AWS cases Wiz documented, with roughly 2.5 million Bedrock calls in total. A separate social media report put cryptocurrency theft enabled by keys stored on Railway at around $371,000.
How do I block global cross-Region routing? Add an explicit deny on bedrock:InvokeModel* and the converse actions with a StringEquals condition on aws:RequestedRegion set to unspecified. A deny on a concrete Region name does not match the global resource evaluation.
Is there proof the resale sites are behind the breaches? No. Wiz states it has no evidence linking them. What it documents is that their operators had access to the stolen keys and were checking them, which shows a live market for the credentials.
Sources
- Wiz — "Black October" for AI Developer Platforms — the consolidated incident analysis, October 30, 2026
- Zeabur — October 2026 security incident (preliminary report) — October 19, 2026
- Zeabur is shutting down: what happens next — October 17, 2026
- Amazon Bedrock — cross-Region inference — geographic versus global comparison
- Amazon Bedrock — Global cross-Region inference — three-part IAM policy and the unspecified deny pattern
- Amazon Bedrock — Geographic cross-Region inference — geography prefixes and IAM example
- Amazon Bedrock — Supported Regions and models for inference profiles
- Amazon Bedrock — IAM policy examples — restricting InvokeModel to a specific model and inference profile
Related Articles
- Claude API Abuse Report 2026: Developer Impact — the demand side of the same market, from Anthropic's own report
- AI API Cost Control Tools 2026 — gateway spend limits and per-key budgets compared
- GPT-5.6 Sol Hits Hugging Face: API Lessons — the guardrail patterns that survive model-layer attacks
- Amazon Bedrock API Review — the platform-level pricing and model overview