Your agent just created three service accounts. Who authorised those?
Access control is built almost entirely to police the spending of authority. Almost nothing polices the minting of it. Agents with infrastructure access do not merely use credentials, they create them, and every credential they create can create more.
Picture a platform engineer at a mid sized company on a quiet Thursday, doing the kind of housekeeping that gets scheduled and then postponed for two quarters. She is reconciling the cloud account's list of principals against the team's inventory of what should exist.
There are eleven service accounts she does not recognise. This is not alarming by itself, because there are always a few, and the usual explanation is a proof of concept that somebody forgot to clean up. So she starts pulling the creation events out of the audit log, expecting to find a colleague's name and a two year old date.
What she finds instead is that all eleven were created in the last five weeks, by the same caller, and the caller is the service principal belonging to the deployment agent the team started running in July. Each creation is a clean, successful, well formed API call. The agent held a valid token. The token's role permitted the operation. The audit log records the caller, the timestamp, the source address and the resulting resource identifier. Nothing failed. Nothing was bypassed. Nothing looks wrong.
And there is no field anywhere in any of those eleven records that answers the question she actually needs answered, which is: which human's authority produced this?
Should AI agents be allowed to create API keys and service accounts? Only under an explicit human signed delegation that names credential creation in its scope, sets limits on lifetime and permissions, and anchors the new principal to a chain leading back to an enrolled person. Otherwise every key an agent mints is an orphan at birth: legitimate, logged, durable, and traceable to no one who can be held responsible for it.
What happens when a credential can create credentials?
Here is the shape of the problem, stated as plainly as it can be.
Most access control thinking treats a credential as a thing that lets you do something: read a bucket, call an endpoint, deploy a service. Under that model, the security question is scope, and the discipline is least privilege. Give each principal the narrowest set of permissions it needs, rotate the secrets, and you have contained the damage any single compromise can cause.
But some permissions are not like the others. The permission to create a new principal is qualitatively different from the permission to read a bucket, because exercising it does not consume anything or accomplish a task. It expands the set of things that hold authority. Creating an IAM user, generating a personal access token, registering an OAuth application, adding a deploy key, provisioning a service account, configuring a webhook with a secret: each of these produces a new, independent, durable holder of permissions that will outlive the session that created it.
The analogy: spending versus minting
Think of authority as money in an economy.
Delegation is spending. You hand some of your purchasing power to someone else for a purpose, and when they spend it, it is gone. Every access control system ever built is designed with this model in mind: audit the transactions, limit the amounts, review the accounts. The whole apparatus of least privilege, rotation and monitoring is a treasury department watching money move.
Credential issuance is minting. It does not move authority from one place to another. It creates new authority that did not exist before, and it does so through a completely ordinary looking transaction. If you built a treasury that scrutinised every payment and left the printing press in an unlocked room, you would have built most enterprise cloud environments.
The analogy breaks in one important way, and the break is instructive. In an economy, minting is centralised precisely because everyone understands what happens when it is not. In a cloud account, minting is a routine API call available to any principal with the right role, including principals that are themselves the product of a previous minting.
Why it compounds rather than merely accumulates
This is the part that matters most, and it is worth being slow about.
If an agent creates eleven service accounts, you have an inventory problem. Annoying, tractable, the kind of thing a quarterly clean up fixes.
But consider what those eleven accounts can do. If any of them carries a role that includes credential creation, and in practice several will because the roles that let you provision infrastructure usually include the roles that let you provision access to it, then each of them can mint further principals. Those principals can mint more. The tree has no natural depth limit, because nothing in the model is counting depth.
Authority is not being divided as it is passed along. It is being reproduced. An agent handed a scoped, time limited task in July can, entirely without malice and entirely within policy, leave behind a subtree of principals in September that no longer has any connection to July's task, July's session, or July's human.
And every one of those principals is invisible to the mechanism you would most expect to catch it. When that engineer leaves the company in November, the offboarding process disables her identity provider account. It does not touch a single one of the principals in the subtree, because none of them names her. We treated this at length in the offboarding post: authority granted to a person is handled reasonably well, and authority that merely flowed through a person is handled not at all. Agent minted credentials are the purest form of the second case, because the person's name never appeared on the artifact even once.
Why does the cloud audit log not answer this?
It seems like it should. The audit log is comprehensive, tamper resistant, and records every API call with its caller. Surely the answer is in there.
The audit log records the calling principal, faithfully and correctly. When the deployment agent creates an access key, the log says the deployment agent created an access key. This is accurate. It is also the wrong level of abstraction for the question being asked, and no amount of log analysis recovers the missing information, because the information was never present in the request.
Follow the chain backwards and you can see where it breaks. The agent acted under a service principal. The service principal was assumed by a workload. The workload was started by a pipeline. The pipeline was triggered by a merge. The merge was approved by an account. Somewhere behind that account there was a person, on some particular day, making some particular decision, and by the time you have traced back that far you have crossed four or five systems, each of which records only its immediate caller, and at least two of which have log retention shorter than the credential's lifetime.
You are not reconstructing a chain. You are doing archaeology, and the answer you get is a guess with a name attached.
What about non human identity governance?
A category of tooling has grown up around exactly this pain, and it is genuinely useful. Non human identity governance products discover principals across clouds and SaaS platforms, attribute ownership where they can, flag stale and over permissioned accounts, and give a team a list to work through. If you have thousands of unattributed service accounts today, this is the fastest way to find out what you actually have, and nothing below should be read as an argument against buying one.
The limitation is structural and the vendors would mostly agree with the characterisation. Discovery is retrospective. It tells you what exists after it exists, and infers ownership from signals such as naming conventions, tags, usage patterns and the audit trail we just established is inconclusive. It is a very good census of a population whose birth records were never kept.
Short lived credentials get proposed as the answer, and they are a real improvement to a different problem, which is the long lived secret sitting in a configuration file for four years. But notice what they do to this problem: shortening a credential's life increases the number of issuance events. If issuance is the unsigned act, then a system that issues every fifteen minutes has more unsigned acts, not fewer. It has reduced the value of any single stolen credential, which is worth doing, while leaving the authorisation question completely untouched.
Workload identity frameworks such as SPIFFE and SPIRE go further and deserve credit for it. They remove long lived secrets from the picture by giving workloads cryptographically verifiable identities derived from attested properties, which eliminates whole classes of secret sprawl. What they establish is that a workload is what it claims to be. What they do not establish, and do not aim to establish, is which human's authority put that workload there with those permissions. The gap is not a flaw in the design, it is outside the design's scope.
The uncomfortable ratio
Estimates of how many non human identities exist per human employee circulate widely, and the numbers vary from the tens to the hundreds depending on who is counting and what they count. Vendor surveys in this space are produced by companies selling inventory products, sample opaquely, and define the term differently from one another, so any specific ratio should be read as directional at best. We wrote about the general phenomenon in the ratio post and in the fan out post.
What is not in dispute, because it follows from arithmetic rather than from a survey, is the direction. Agents create principals faster than humans do, they do it continuously rather than in bursts, and each principal they create can create more. Whatever the ratio is today, the mechanism that determines it is compounding.
Do attackers actually use this, or is it theoretical?
They use it, and the pattern is old enough to have a shape.
The Shai-Hulud campaign against the npm ecosystem, first observed in September 2025 and recurring in later waves, is the clearest published example. Analyses from Elastic Security Labs, Kaspersky and Sygnia describe a self replicating supply chain worm that began with compromised maintainer credentials and propagated by using those credentials to reach further: harvesting developer and cloud secrets, manipulating continuous integration workflows, and republishing packages under accounts it had come to control. Reporting described propagation across hundreds of packages, with the affected packages accounting for very large monthly download volumes. The specific counts differ between accounts and across waves, so treat any single number as approximate, but the mechanism is consistent and it is the point: the compromise scaled because the credentials it stole were used to obtain and abuse further credentials.
The Snowflake customer campaign of 2024 shows the same principle from the other direction. Mandiant's analysis of the activity it tracked as UNC5537 described an actor using credentials harvested by infostealer malware, in many cases from contractor machines, to authenticate to customer tenants that lacked multi factor authentication, affecting at least 165 organisations. We looked at the volume dimension of that incident in the bulk export post. The identity dimension is that valid credentials, obtained rather than forged, produced a great deal of successful authentication and a great deal of legitimate looking activity.
What both have in common is that no step in either was an exploit in the traditional sense. Every credential was valid. Every operation was permitted. The persistence and the scale came from authority being obtained and, where useful, extended.
The agent case is the same mechanism with the malice removed and the volume raised. An agent doing exactly what it was asked to do, provisioning infrastructure competently on your behalf, produces the same expanding subtree of unattributed principals that an attacker would produce deliberately. That is not a comforting observation. It means the defensive signal you might hope for, that credential creation is unusual and therefore detectable, is being eliminated by normal operations.
What would signed issuance look like?
Treat credential creation as its own action class, distinct from credential use, and require that every issuance event be traceable to a human decision. That decision can be immediate, or it can have been made in advance and bounded, but it has to exist somewhere as an artifact.
In practice this means one of two paths for any issuance.
The direct path. A human signs the creation of the principal, on an enrolled device, over an object naming what is being created and with what powers. This is appropriate for high privilege principals, for anything in production, and for the first time a given automation asks for a given class of credential.
The delegated path. A human has previously signed a delegation whose scope explicitly names credential creation, with constraints on what may be created, and the agent operates under that. This is what makes routine automation viable, and the constraints are where all the design work lives.
{
"type": "delegation",
"delegator": "did:manav:8f3a...b21c",
"delegateKey": "ed25519:pk_agent_deploy_7c4a",
"scope": {
"actions": ["iam.createServiceAccount", "iam.createAccessKey"],
"constraints": {
"max_ttl": "24h",
"permission_boundary": "arn:aws:iam::acct:policy/AgentProvisionedBoundary",
"environments": ["staging"],
"max_principals_per_day": 5,
"may_grant_creation_rights": false
}
},
"notBefore": "2026-09-17T09:00:00Z",
"notAfter": "2026-09-24T09:00:00Z",
"maxChainDepth": 2,
"revocationId": "rv_3f81c0d4"
}
Two of those constraints are doing unusual work and deserve calling out.
may_grant_creation_rights: false is the one that stops the compounding. It says that principals created under this delegation may not themselves hold the power to create principals. This is the depth limiter that the cloud IAM model lacks, and it converts an unbounded tree into a bounded one. In most environments this single constraint would eliminate the majority of the sprawl, because most agent provisioned accounts have no legitimate need to provision further accounts and receive that power only because it came bundled in a convenient role.
permission_boundary uses an existing cloud primitive to enforce that anything created under this delegation cannot exceed a defined ceiling, regardless of what policy the agent attaches. Cloud providers already offer this and it is underused.
The credential's birth certificate
The second half of the design is that the created principal carries a reference to the receipt that authorised it, in whatever metadata field the platform provides. Tags on a cloud principal, a description field on a token, an annotation on a Kubernetes service account: the mechanism is unglamorous and it is what makes the whole thing work.
# Provisioning gate: no receipt, no principal
receipt=$(manav authorize \
--action iam.createServiceAccount \
--payload '{"name":"billing-sync","env":"staging","boundary":"AgentProvisionedBoundary"}' \
--under-delegation "$AGENT_DELEGATION") || exit 1
aws iam create-service-account --name billing-sync \
--permissions-boundary arn:aws:iam::acct:policy/AgentProvisionedBoundary \
--tags Key=manav.receipt,Value="$(echo "$receipt" | manav receipt id)" \
Key=manav.anchor,Value="did:manav:8f3a...b21c"
Now the eleven mystery accounts from Thursday morning are not mysteries. Each one carries the identifier of the receipt that authorised its creation, and that receipt names the delegation, and the delegation names the human who signed it. The archaeology becomes a lookup.
What does a chain give you that an inventory does not?
Three things, and the third is the one that changes operational reality.
Attribution at creation rather than inference afterwards. The provenance is recorded when the principal is born, by the process creating it, rather than reconstructed later from naming conventions and log fragments. This is the difference between a birth certificate and a forensic estimate of age.
A verifiable answer rather than a trusted one. The receipt is a signature over a canonical object, checkable against a published key. An auditor, an incident responder or an insurer can verify it without access to your cloud account and without trusting your inventory tooling.
Revocation that walks downward. This is the operational payoff. When authority is a chain anchored in a human signature, revoking the anchor invalidates every delegation beneath it, and any principal that carries a receipt referencing that chain can be found and disabled by a single query rather than by a search. The offboarding conversation changes from "find everything she touched" to "revoke her anchor and sweep the descendants". We covered the mechanics and the honest limits of propagation in the revocation post, and the general model in the authority graph post and the chain depth post.
| Question | Cloud audit log | NHI discovery tooling | Chain anchored issuance |
|---|---|---|---|
| What principals exist? | Partially, by replay | Yes, this is its strength | Yes, for governed paths |
| Which principal created this one? | Yes | Sometimes | Yes |
| Which human authorised it? | No | Inferred at best | Yes |
| Under what scope and limits? | No | No | Yes, in the delegation |
| Can a third party verify the answer? | No | No | Yes, offline |
| Does revoking a person remove it? | No | Flags it for review | Yes, by walking the chain |
| Covers principals created outside the system? | Yes | Yes | No |
That last row is deliberate, and it is the honest heart of the comparison. Discovery tooling sees everything, including what you did not govern. Chain anchored issuance sees only what flowed through it. They are complements, and any team with existing sprawl needs both: discovery to find what is already there, issuance controls to stop the pile growing.
What does this not fix?
Ungoverned paths remain ungoverned. An agent holding raw cloud credentials, pasted into an environment variable by a well meaning engineer, creates principals entirely outside this model. Nothing in a delegation chain constrains an API call made with a static key. Reducing the number of ungoverned paths is a separate, longer programme, and this control is worth little until that programme is underway.
It does not evaluate the request. A human who signs a delegation permitting broad credential creation, because an engineer said the pipeline needed it and it was late, has authorised exactly what they authorised. The receipt records the decision faithfully, including when the decision was poor. Accountability is not the same as wisdom.
Legitimate automation will break at first. Any team that turns this on without measuring first will discover that their pipelines create far more principals than anyone believed, and several will fail. The correct sequence is to run in observation mode, count real issuance events over a few weeks, then write constraints that fit the measured reality rather than the imagined one.
Cloud provider integrations are not shipped. Delegation chains, per action signatures and offline verifiable receipts exist today, and the pattern above is implementable against the signing API with a wrapper around your provisioning path, as the agent authorization demo shows in miniature. First party integrations with cloud IAM, code hosting platforms and Kubernetes are future work. Anyone telling you this installs in an afternoon is selling.
It adds a dependency to your provisioning path. A gate that must be consulted before a principal can be created is a gate that can fail. The design needs an explicit answer for what happens when verification is unavailable, and for high volume automation the honest answer is usually a pre signed delegation with generous limits rather than a synchronous check, which trades precision for availability.
What to do this week
The first three items are free and will tell you whether you have this problem before you spend anything on it.
- Count your issuance events. Query the last ninety days of audit logs for credential creation operations: access key creation, service account creation, token issuance, OAuth application registration, deploy key addition. The raw count surprises most teams.
- Split that count by caller type. How many were created by a human's interactive session, and how many by a service principal or automation? The ratio between those two numbers is the size of your attribution gap, expressed in one figure.
- Find the principals that can create principals. Enumerate every role in your environment that includes credential creation permissions, and every principal holding one. This list is almost always longer than the team expects, because creation rights arrive bundled inside convenient administrative roles.
- Pick one recent agent created principal and trace it by hand. Time yourself. However long it takes to get from the principal to a named human is how long every incident investigation will take, multiplied by the number of principals involved.
- Apply a permission boundary to agent provisioning. This uses a primitive your cloud provider already offers, requires no new vendor, and puts a ceiling on anything your automation creates.
- Remove creation rights from created principals. Wherever an automation provisions accounts, ensure those accounts cannot themselves provision. This one change bounds the depth of the tree and is usually the highest value hour of work available.
- Start tagging. Even before any signing, require that every programmatically created principal carries a tag identifying the human owner and the purpose. It is weaker than a receipt because a tag is an assertion rather than a proof, and it is dramatically better than nothing.
- Write the delegation you would sign. Draft the constraints you would actually be comfortable granting your deployment agent for a week: which operations, what lifetime ceiling, what boundary, how many per day, and whether created principals may create more. Whether or not you implement signing, the exercise of writing it down is clarifying.
Frequently asked questions
Should AI agents be allowed to create API keys at all? Yes, for most teams the alternative is worse, because blocking it entirely pushes engineers toward static long lived credentials shared by hand. The workable position is that agents may create credentials under an explicit delegation that limits scope, lifetime and permission ceiling, that names credential creation in that scope rather than inheriting it accidentally, and that forbids created principals from creating further principals.
How do you trace a service account back to a person? Today, usually by inference: naming conventions, tags, the audit log entry for its creation, and asking around. Each of those is a guess. The reliable method is to record the authorising receipt in the principal's metadata at creation time, so the answer is a lookup rather than an investigation.
Do short lived credentials solve this? They solve a different and real problem, which is the value of a stolen secret. They do not address authorisation of issuance, and by increasing issuance frequency they arguably enlarge the unsigned surface. Both controls are worth having and they are not substitutes for one another.
How is this different from workload identity such as SPIFFE? Workload identity establishes that a workload is what it claims to be, using attested properties rather than shared secrets, and it removes long lived secrets from the environment. It is excellent at that. It does not record which human's authority caused that workload to exist with those permissions, which is a different question that its design does not attempt.
Will this break our automation? Almost certainly, if you enable enforcement before measuring. Run in observation mode first, count actual issuance events over several weeks, and write constraints against the measured behaviour. Teams that skip the measurement step generate an outage and then disable the control, which is worse than never starting.
What about credentials created before any of this existed? They stay outside the model, and discovery tooling remains the right instrument for finding and attributing them. Chain anchored issuance stops the pile growing; it does not retroactively document the pile you already have.
Who should hold the anchor for an agent that serves a whole team? A named individual, not a group, because the point of the anchor is that a specific person is accountable and a specific revocation is possible. Rotate the responsibility deliberately if you must, by issuing a fresh delegation under the new owner, rather than letting the original anchor persist past its owner's tenure.
Sources
- Elastic Security Labs, analysis of the Shai-Hulud npm supply chain worm and its later waves. Elastic Security Labs
- Kaspersky Securelist, technical analysis of the Shai-Hulud worm infecting npm packages. Securelist
- Sygnia, threat report on the return of Shai-Hulud and software supply chain abuse. Sygnia threat reports
- Mandiant, analysis of the UNC5537 campaign against Snowflake customer tenants using infostealer derived credentials. Google Cloud Threat Intelligence
- SPIFFE and SPIRE, the workload identity specification and reference implementation. spiffe.io
- IETF RFC 8693, OAuth 2.0 Token Exchange. RFC 8693
- AWS, IAM security best practices including permissions boundaries and access key management. AWS IAM best practices
- Kubernetes, the TokenRequest API for service account token issuance. Kubernetes TokenRequest
- GitHub, documentation on managing personal access tokens and fine grained permissions. GitHub personal access tokens
- NIST, Zero Trust Architecture, SP 800-207. NIST SP 800-207
- Manav developer documentation on delegation chains, scope constraints and offline receipt verification. manav.id/docs
Least privilege tells you how much authority a principal holds. Nothing in your stack tells you who decided that principal should exist.