Non-human identity: 109 machine accounts per human, and the offboarding process that never runs
Service accounts, API keys, OAuth grants and CI/CD secrets hold broader access and longer-lived credentials than any employee would be permitted to carry, and none of them appear in an access review. Inventory, short-lived tokens, and the IAM calls that give the game away.
8 min read3 views
Palo Alto Networks' 2026 Identity Security Landscape report, drawn from 2,930 security decision-makers, put a number on something most CISOs already suspected: machine identities now outnumber human identities 109 to 1 inside the average enterprise, up from 82 to 1 the year before.
That is not a plateau. It is a third again in twelve months, and it is happening while the governance model for these identities has not meaningfully changed since a service account was something an engineer provisioned once and forgot about.
Every identity security programme most enterprises have built assumes a human on the other end. Quarterly access reviews a person approves. MFA a person completes. Offboarding triggered when a person leaves. Non-human identities, meaning service accounts, API keys, OAuth tokens, CI/CD secrets and now AI agent credentials, do not fit that lifecycle. They are not reviewed quarterly. They do not authenticate with MFA. They do not leave. They accumulate, and they hold broader access, longer-lived credentials and lighter oversight than any human account would ever be permitted to carry.
Why this category never got governed
The original IAM problem was human access: too many admins, privilege creep across job changes, orphaned accounts after someone left. The tooling built to fix it, access reviews, joiner-mover-leaver workflows, PAM platforms, was designed around a lifecycle humans actually have.
Service accounts had none of that. An engineer provisioned one to make something work. It never appeared in an HR system, it never had a manager, and the review process that existed had no hook to catch it.
API keys were treated as configuration, living in .env files and secrets managers with a rotation policy of "whenever someone remembers". OAuth grants were treated as one-time integration decisions: a SaaS tool needed calendar and email access, someone granted it at setup, usually at a broader scope than the integration ever used, and the review that should have followed never happened at all.
None of this was a deliberate choice to under-govern. It was governance infrastructure built for one identity type, silently excluding another that grew alongside it, and it is now being accelerated by AI agents that request and hold credentials with far less human review than a new employee's access would get.
What this looks like in practice
A serverless function that needs read access to one S3 bucket gets AdministratorAccess because it is the fastest path to "it works", with a plan to tighten it later. Later does not come, and the function runs for two years with standing admin, sometimes with trust relationships letting it assume roles in other accounts.
A developer commits an AWS key, notices immediately, and force-pushes it out of history. The key itself is rarely rotated in that same moment, so it is still valid, and it was already indexed by an automated scanner in the minutes between push and removal.
A SaaS integration used for six months and abandoned still holds the OAuth grant it was given at setup, broad read and write to email and calendar. When that SaaS vendor is compromised eighteen months later, the attacker inherits every scope the original grant carried.
A service account provisioned for a project that ended two years ago still has that project's permissions, including write access to production, because nobody tracked that the project ended and nobody owned the decision to revoke it.
This is not hypothetical risk-modelling. The wave of Snowflake customer compromises in 2024 followed exactly this shape: valid credentials for accounts without MFA, used by an attacker who did not need to exploit anything, doing what those credentials had been quietly authorised to do for years.
How an attacker actually walks this path
None of it requires phishing anyone or exploiting a CVE.
Credential discovery starts with public repositories, misconfigured buckets and exposed config files, all continuously indexed by automated scanners. A key pushed and removed inside thirty seconds can still be caught.
From a recovered credential, tooling systematically tests which API calls succeed, mapping the identity's full capability rather than stopping at the first usable permission:
# What does this key actually have?
python enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE --secret-key ...
# Where can it get to from there?
pmapper --profile ir-readonly graph create
pmapper --account 123456789012 query -s 'preset privesc *'
From there, IAM misconfigurations often provide a path upward even when the initial credential cannot do what the attacker wants directly. iam:PassRole is the canonical case: an identity holding it can attach a more privileged role to a compute resource it controls and execute under that identity instead.
In organisations using AWS Organizations, trust relationships between accounts frequently let a role in one account assume a role in another with no additional credential at all. That is a lateral movement path that exists purely because nobody mapped the trust graph before granting it.
What actually closes the gap
Inventory first, because everything else depends on knowing what you have. Every service account, every API key and the service it belongs to, every OAuth grant and its scope, every execution role and attached policy, every CI/CD secret. Purpose-built tooling exists, and so do cloud-native options: AWS IAM Access Analyzer, Azure Entra workload identities, GCP's IAM recommender. They surface credentials, scopes and last-used timestamps that most teams have simply never had visibility into.
Then replace long-lived credentials with short-lived tokens wherever the platform allows it. This is the single highest-leverage change and it is architectural rather than procedural. A credential valid for fifteen minutes has a blast radius bounded by fifteen minutes. A credential valid for three years has a blast radius bounded only by whenever someone happens to notice, and for most of the identities above, that notice never comes.
# GitHub Actions: OIDC federation instead of a long-lived AWS key
name: deploy
on:
push:
branches: [main]
permissions:
id-token: write # required to request the OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: us-east-1
# The action defaults to a 1 hour session. Ask for less.
role-duration-seconds: 900
- run: aws sts get-caller-identity
No stored key exists to leak, and the credential that is issued expires before most scanners would finish indexing it. The role's own trust policy should pin the sub claim to the specific repository and branch, otherwise any repository in the organisation can assume it.
Every identity needs a named owner, not necessarily its creator, but someone accountable for reviewing, rotating and eventually revoking it. An identity with no owner is an identity nobody will ever decide to remove.
Least privilege has to be re-run, not declared once. IAM Access Advisor and its Azure and GCP equivalents show last-used timestamps per permission. Anything unused for 90 days is a removal candidate, checked quarterly, because new scope creeps in every time someone expands access under deadline pressure and nobody walks it back afterwards.
Exposure triggers rotation before investigation, which inverts the instinct most teams still have to check whether a leaked key was actually used before deciding whether it is worth the disruption to rotate. The time between exposure and rotation is the blast radius window, and every minute spent investigating first is a minute that window stays open for no reason.
Detection
- A service account dormant for 180 days that suddenly makes API calls. Low effort, high fidelity, and almost nobody alerts on it.
- Access from an unexpected IP range or geography. A Lambda role's credentials authenticating from a residential IP in another country is the cloud equivalent of a badge swipe in two cities at once.
- A burst of
DescribeandListcalls across many services in a short window. This is the signature of automated enumeration tooling and it looks different from normal service traffic even for accounts that call APIs constantly. iam:PassRole,iam:CreateRole,iam:AttachRolePolicyoriam:PutRolePolicyfrom a service identity that has never made them before. These are the exact permissions used in cloud privilege escalation chains, so first use is worth a page.- OAuth grant scopes monitored for change through whatever administrative API the SaaS platform exposes, flagging new grants and scope expansions as they happen rather than during an annual review that arrives long after the window has closed.
Take this away
The human identity problem has had twenty years of governance investment behind it. The non-human identity problem grew up alongside it, unmanaged, and the ratio between the two widened by a third in a single year.
Inventory, short-lived credentials, named ownership and scheduled review are not novel controls. They are the same controls that already exist for human identities, extended, finally, to the category that was excluded from them by assumption rather than by any deliberate design decision.
Two questions are answerable this week on any cloud account you own: how many non-human identities exist, and how long does each of their credentials stay valid.
Further reading
Was this useful?
Comments
Loading comments…