Every cloud generation has a resource type that arrives faster than its governance. Last decade it was the storage account: convenient, everywhere, reachable by default, and the subject of a breach headline every month for years. I wrote about hunting yours in July. This decade's version is the LLM endpoint, with one upgrade for the attacker. They no longer need to find your data to profit from your misconfiguration. The endpoint itself is the product, and it bills to you.
The trade even has a name now, LLMjacking, coined by Sysdig's threat research team when they first caught it in the wild. Their recent numbers: credential theft aimed at AI services rose 376% between the last quarter of 2025 and the first of 2026. Brokers validate stolen keys in bulk and resell them through reverse proxies on underground forums, and Sysdig put the potential burn on one hijacked frontier-model account at over $100,000 a day. The supply side keeps pace: GitGuardian counted 1.27 million AI-service secrets in public GitHub commits during 2025, up 81% on the year.
None of this is theoretical for Azure estates. Microsoft has been in court with Storm-2139, a group it says harvested exposed Azure OpenAI keys, wrapped them in a purpose-built web app, and sold access with the content filters stripped off. The abuse ran inside the victims' own subscriptions, on their invoices.
Why inference is worth stealing
A stolen virtual machine still has to be turned into money, through cryptomining or resale as a proxy. An inference endpoint skips that step. It is metered compute with a resale market attached, and the meter runs on someone else's payment method.
It is also quiet. The traffic looks like API calls because it is API calls, arriving at a legitimate endpoint inside a legitimate subscription. Nothing is exfiltrated and nothing falls over. On most estates the first detection control that fires is the invoice.
The three ways to host a model in Azure
The hosting decision is simpler than the marketing suggests. Three shapes cover it, and the right one falls out of two questions: whose model, and whose GPUs.
Serverless, from the catalogue. Microsoft Foundry (Azure AI Foundry until June's rename) fronts the hosted-model market: the Azure OpenAI models, Anthropic's Claude family (generally available on Microsoft-hosted infrastructure since Build), Mistral, Llama, and a long tail of others. You pay per token and Microsoft runs the GPUs. This is the right default for almost everyone, and it is the shape this article secures, because what you get back is the thing attackers want: an endpoint and a pair of API keys.
Managed compute. For open-weight models, Azure will run the model you choose on dedicated GPU instances you size, billed per hour rather than per token. You take on quota wrangling and capacity planning; you get model choice and a deployment that sits properly inside your network design.
Self-hosted on AKS. vLLM or similar on your own GPU node pools. Full control and the full operational burden, so it needs a forcing reason: sovereignty rules the managed options cannot meet, or token economics at a scale where dedicated hardware wins.
The demo path is identical for all three: a public endpoint and a credential in an app setting, stood up in an afternoon. The production path is also identical in shape, which is the useful news, because none of it is AI-specific.
The demo-day defaults
An Azure OpenAI or AI Services resource arrives with key authentication switched on: two keys, no expiry, visible to anyone whose role can list them. Public network access is on by default too. These are the same two defaults that made the storage-account decade what it was, and the same two settings close them.
Kill the keys first. The resource takes
disableLocalAuth,
after which the only way in is an Entra ID token, and a leaked connection
string is a string. Your applications authenticate with their managed
identity and a data-plane role (for inference, Cognitive Services OpenAI
User), which is the same
identity-is-the-perimeter move every
other Azure PaaS service has been converging on. A scraper cannot resell a
managed identity.
Then take the endpoint off the internet: public network access off and a private endpoint in its place, with the DNS zone wired up so resolution stays inside your network. In Terraform, the account half of that looks like this:
resource "azurerm_cognitive_account" "llm" {
name = "oai-myapp-prod"
location = azurerm_resource_group.ai.location
resource_group_name = azurerm_resource_group.ai.name
kind = "OpenAI"
sku_name = "S0"
custom_subdomain_name = "oai-myapp-prod"
local_auth_enabled = false
public_network_access_enabled = false
identity {
type = "SystemAssigned"
}
}
The working example, with the private endpoint, the DNS zone, a model deployment and the role assignment for a caller identity, is in the blog-examples repo.
Two settings on one resource is hygiene. What makes it governance is Azure Policy: built-in policies exist for exactly these controls (key access disabled, public network access disabled, private link required), so assign them in audit mode and the AI resources you did not know about report themselves. The hackathon deployment from March is the one this catches.
Tripwires, because keys leak anyway
Some of your estate will not be able to turn keys off tomorrow. Vendor tools still assume them, and a proof of concept always moves faster than its retrofit. For that tail, make the abuse loud instead.
A cost alert on every AI resource is the cheapest control in this article. LLMjacking is quiet in the logs and deafening on the meter, so a budget threshold that pages someone turns invoice-time detection into same-day detection. Behind that, send diagnostic logs to Log Analytics so you can see token volume by caller, and if you run Defender for Cloud, its AI services plan watches for exactly this abuse pattern against the endpoints themselves.
This week, in four moves
- Inventory the estate. One Resource Graph query lists every AI account and the two settings that matter:
kusto
resources
| where type == "microsoft.cognitiveservices/accounts"
| project name, kind, resourceGroup,
localAuthDisabled = properties.disableLocalAuth,
publicAccess = properties.publicNetworkAccess
Anything with localAuthDisabled empty or false and publicAccess
enabled is carrying demo-day defaults in production.
2. Disable local auth wherever nothing breaks, and rotate the keys on
whatever remains. What's left is a named list with an owner, not a
surprise.
3. Assign the built-in policies in audit mode. The report is your backlog,
and the next hackathon lands inside the guardrail instead of outside it.
4. Put a cost alert on every AI resource, scoped tight and set low.
Nobody notices a stolen key that costs £40 a day inside a £2m bill; a
per-resource budget notices.
The storage-account era taught the lesson once: defaults chosen for demo convenience become estate-wide exposure the moment a resource type gets popular. LLM endpoints got popular faster than any resource type Azure has shipped. The controls above are not new, and that is the point. They were waiting for this.
More useful tidbits coming — one a week.