When several applications run under one service account, IAM role or API key, compromising the weakest of them hands the attacker the access of all of them, and the logs can no longer say which workload did what. OWASP lists this as NHI9:2025 NHI Reuse in the Non-Human Identities Top 10, and rates it the most widespread weakness on the list. This guide explains how OWASP defines and rates the risk, what "one identity per workload" means on each major platform, how to split shared identities without outages, and how to evidence the result. It is for platform and IAM engineers, application owners and the assessors who review NHI programmes.
Key takeaways
- Reuse is the norm, not the exception. OWASP rates prevalence Widespread because tailoring an identity to every workload is hard, so teams share roles and keys.
- Impact follows privilege. OWASP rates technical impact Low only where least privilege is in place; a shared identity accumulates the union of every consumer's permissions.
- Attribution is the hidden cost. Google Cloud notes that audit logs show the service account, not the application, and Microsoft recommends system-assigned identities where you must log which resource acted.
- Uniqueness has two halves. Each component gets its own NHI, and only that component can authenticate as it. A unique identity whose key is copied elsewhere is still reused.
- Federation makes splitting cheap. Platform-issued identities (IAM roles on compute, managed identities, Kubernetes service accounts, SPIFFE IDs) cost little to multiply; static keys do not.
What it is and who it applies to
OWASP defines NHI Reuse as using the same NHI across different applications, services or components, "even if they are deployed together". If the NHI is compromised in one place, the attacker can use it everywhere the same credentials are accepted. OWASP adds two consequences that matter in practice: reuse complicates breach response, because revoking the identity breaks every consumer at once, and it weakens audits, because activity cannot be tied to one system.
The risk sits with anyone who issues or consumes machine identities:
- Cloud platform teams: one AWS IAM role attached to many functions or instances, one Azure service principal or user-assigned managed identity used by several apps, the Compute Engine default service account running unrelated VMs.
- Kubernetes operators: pods that run under the namespace
defaultservice account, or a single privileged service account shared by orchestration and application pods. - Application teams: one third-party API key embedded in several applications or microservices.
- Integration and automation owners: one "integration user" or bot token used by many scripts, RPA jobs or AI agents.
NHI9 is distinct from its neighbours. NHI8 Environment Isolation is reuse across lifecycle environments; NHI10 Human Use of NHI is people sharing a machine identity; NHI5 Overprivileged NHI is the privilege that reuse tends to inflate. See the OWASP NHI Top 10 NHI8 Environment Isolation Guide and the OWASP NHI Top 10 NHI10 Human Use of NHI Guide.
Structure and key requirements
The OWASP entry uses the project's standard layout: a rating table built on the OWASP Risk Rating Methodology (three-point scale, worst-case impact), a description, examples, "How To Prevent", references and data points.
| Factor | NHI9 rating | OWASP's reasoning (paraphrased) |
|---|---|---|
| Exploitability | Hard | Reuse depends on a separate initial access vector; the attacker must already be in the environment. |
| Prevalence | Widespread | Very common, for example one IAM role or one API key for several workloads. |
| Detectability | Hard | Many different workloads can use the same NHI, so the reuse is hard to see. |
| Technical impact | Low | Depends on the NHI's privilege; low where least privilege is adopted. |
| Business impact | Specific | Depends on what the combined consumers can reach. |
OWASP gives three examples: a Kubernetes service account shared by many pods, including orchestration pods, so one vulnerable pod yields cluster-wide actions; one API key used by several applications for a third-party service; and the same cloud credentials (AWS IAM roles, Azure service principals) used by services of different security levels, so a weak service exposes the resources of a strong one. Its data points include a Chronicle cross-customer bucket access case and the 2024 .env extortion campaign.
The "How To Prevent" requirements are:
- Unique NHI per application or service: each logical component operates under its own NHI, and the ability to authenticate as that NHI is limited to that component.
- Unique NHIs per environment: each environment uses distinct NHIs when talking to other systems (the NHI8 requirement restated).
- Least privilege: each NHI holds only what its function needs.
- Audit and review: audit all NHIs with their access grants and assigned components, and review regularly that they are not reused and remain least privilege.
Identity and NHI requirements
The table shows how "one identity per workload" is implemented on each platform, and where the platform default pushes towards reuse.
| Platform | Default that encourages reuse | Per-workload pattern |
|---|---|---|
| Kubernetes | Pods with no serviceAccountName get the namespace default service account | One ServiceAccount per Deployment, RBAC Role bound to it, automountServiceAccountToken: false where the API is not needed, projected tokens with an audience. See the Kubernetes NHI Security Guide. |
| AWS | One broad role reused as the execution role for many functions or instance profiles | One IAM role per function or service, policies generated from CloudTrail activity with IAM Access Analyzer, last accessed data to trim |
| Azure | A user-assigned managed identity shared to cut role assignments | System-assigned identity where per-resource attribution and lifecycle matter; user-assigned only for replicated instances of the same workload |
| Google Cloud | The Compute Engine default service account, historically granted Editor automatically | A dedicated service account per application with a purpose prefix; the iam.automaticIamGrantsForDefaultServiceAccounts constraint (enforced by default for organisations created on or after 3 May 2024). See the Google Cloud IAM and Service Accounts Guide. |
| Third-party APIs | One account-level API key pasted into every app | One key per consuming application, named after it, with the vendor's narrowest scope |
| Service mesh and SPIFFE | One certificate or identity for a whole cluster | A SPIFFE ID per workload, for example spiffe://example.org/billing/payments, issued through the Workload API |
When sharing is acceptable
Not every shared identity is a finding. Microsoft's guidance supports one user-assigned identity for replicated resources, such as a scale set or several instances of the same app, because they are the same logical component. The test is OWASP's own wording: one identity per logical system component. Sharing across replicas of one component is fine; sharing across different components, owners or trust levels is NHI9.
- Choose per-resource (system-assigned) identities when you need to know which resource acted, or when permissions must disappear with the resource.
- Choose a per-component shared identity for horizontally scaled replicas, pre-provisioned access before deployment, or very rapid resource creation.
- Never share between components with different owners, different data sensitivity, or different exposure (an internet-facing service and a back-office job).
Microsoft also warns that anyone who can run code on a resource can use every identity attached to it, and that anyone allowed to assign a managed identity can attach it elsewhere. Restrict who can assign identities, not only who can create them. See the Service Account Security Guide.
Implementation steps
- Build a consumer map. For every NHI, list each workload that authenticates as it. Sources: CloudTrail and Cloud Audit Logs by principal and source, Google Activity Analyzer, Entra service principal sign-in logs, Kubernetes pod specs (
spec.serviceAccountName), and the vendor's API key usage reports. OWASP's data points note that consumer identification is a capability practitioners rank highly. - Classify each shared NHI. Replicas of one component (acceptable), different components with one owner (split), different owners or trust levels (split first).
- Rank by blast radius. Order by privilege held, number of consumers and the exposure of the weakest consumer. A shared identity with one internet-facing consumer and admin rights goes first.
- Create per-workload identities from code. Define each new identity in infrastructure as code with name, owner and environment tags, and generate its policy from observed use (IAM Access Analyzer policy generation, Google role recommendations) rather than copying the shared policy.
- Migrate one consumer at a time. Point a single workload at its new identity, watch for access denied errors for a defined soak period, then move the next. Start with non-production.
- Shrink, then disable, the old identity. As consumers leave, remove the permissions only they needed. When none remain, disable it (Google recommends disabling before deleting, since a recreated account with the same name is a new identity), then delete it and its role assignments.
- Prevent regression. Add policy checks: Kubernetes admission rules that reject pods using the
defaultservice account, IaC review rules that flag a role attached to more than one distinct workload, and a rule that new API keys must be registered to one application. See the Kubernetes Admission Control Guide.
Rollback: if a migrated workload fails, switch only that workload back to the old identity (which is still enabled until the last consumer has moved), record the missing permission, and retry. Never solve a failure by widening the new identity to match the old one.
Small and large organisations
- Small teams: aim for one identity per application and per environment, and remove the platform default accounts from use. That handles most exposure without heavy tooling.
- Large estates: make identity creation a self-service, templated step in the deployment path so a new identity costs nothing, and assign each NHI a named owner so shared identities have someone to answer for them. See the Service Account Inventory Template.
Evidence and assessment
| Evidence | Source | What good looks like |
|---|---|---|
| NHI to consumer map | Inventory joined with authentication logs | Each NHI has one logical consumer, or a documented replica set |
| Shared NHI exception register | Risk register | Each exception has an owner, reason and expiry |
| Default account usage | Kubernetes pod specs, Google default service account activity | No workloads on default service accounts |
| Policy provenance | IaC repository, Access Analyzer or role recommendation reports | Per-workload policies derived from observed use |
| Review records | Periodic access review output | Reuse and privilege reviewed on a set cycle, as OWASP requires |
Detection and metrics
- Detect: alert when one NHI authenticates from a new source workload, host, cluster or network that is not in its consumer map; when an API key is used from more than its registered application's egress addresses; and when a pod is created under a
defaultservice account. - Metric 1: percentage of NHIs with exactly one logical consumer.
- Metric 2: number of distinct workloads per NHI (watch the maximum, not only the mean).
- Metric 3: workloads running on platform default service accounts (target zero).
- Metric 4: percentage of NHIs with a named owner and consuming component recorded.
- Metric 5: mean time to revoke a single compromised workload's identity without affecting others.
Mapping to other frameworks
IDs below were checked against NIST SP 800-53 Rev. 5, NIST CSF 2.0 and MITRE ATT&CK v20.
| Framework | Control or technique | Relevance to NHI9 |
|---|---|---|
| NIST SP 800-53 Rev. 5 | AC-2(9) Restrictions on Use of Shared and Group Accounts | Shared accounts only where they meet defined conditions |
| NIST SP 800-53 Rev. 5 | IA-4 Identifier Management; IA-9 Service Identification and Authentication | Unique identifiers for services and their authentication |
| NIST SP 800-53 Rev. 5 | AC-6 Least Privilege; AU-6 Audit Record Review, Analysis, and Reporting | Per-workload privilege and attributable audit trails |
| NIST CSF 2.0 | PR.AA-01, PR.AA-05 | Service identities managed; permissions least privilege and reviewed |
| CIS Controls v8.1 | 5.5 Establish and Maintain an Inventory of Service Accounts; 6.8 Define and Maintain Role-Based Access Control | Inventory with owner and purpose; access defined per role |
| ISO/IEC 27001:2022 Annex A | 5.16 Identity management; 8.2 Privileged access rights | Unique identities and controlled privilege |
| MITRE ATT&CK v20 | T1078.004 Cloud Accounts; T1528 Steal Application Access Token; T1550.001 Application Access Token | Stealing one shared credential or token and using it against every system that trusts it |
Common pitfalls
- Splitting names but not keys: creating per-app service accounts while every app still loads the same static key from a shared secret path. Bind each workload to its own credential. See the OWASP NHI Top 10 NHI7 Long-Lived Secrets Guide.
- Copying the shared policy: giving each new identity the old shared policy recreates NHI5 many times over. Generate policies from observed use.
- Relying on default service accounts: Kubernetes assigns
defaultwhen no account is set, and Google default service accounts may carry Editor on older organisations. - Ignoring who can assign identities: per-workload identities lose their value if many people can attach any identity to any resource or run code on a resource that holds one.
- One integration user for everything: SaaS integrations, scripts and AI agents sharing one bot account or token, so one compromised connector exposes all. See the OWASP NHI Top 10 NHI3 Vulnerable Third-Party NHI Guide.
- Deleting without disabling: removing a shared identity in one step breaks unknown consumers and, on Google Cloud, a recreated account with the same name does not regain old bindings.
Practitioner checklist
- Every NHI has a recorded owner, consuming component and environment.
- A consumer map, built from authentication logs, shows which workloads use each NHI.
- Shared NHIs are limited to replicas of one component, or held in an exception register with expiry dates.
- No workload runs on a Kubernetes
defaultservice account or a cloud default service account. - New workloads get their own identity automatically from a template in the deployment path.
- Per-workload policies are generated from observed use, not copied from the shared identity.
- Only the owning component can authenticate as its NHI; static keys are not shared through common secret paths.
- Alerts fire when an NHI is used from a source outside its consumer map.
- Reuse and least privilege are reviewed on a fixed cycle, as OWASP requires.
Standards and references
- OWASP: NHI9:2025 NHI Reuse
- OWASP: Non-Human Identities Top 10
- NIST: SP 800-53 Rev. 5
- Kubernetes: Service Accounts
- Google Cloud: Best practices for using service accounts
- Microsoft Learn: Managed identity best practice recommendations
- AWS: Security best practices in IAM
- SPIFFE: SPIFFE Concepts
Related NHI Mgmt Group resources: OWASP NHI Top 10 NHI5 Overprivileged NHI Guide · Cloud Workload Identity Guide · Workload Identity Federation Guide · Kubernetes Service Account Token Guide · Non-Human Identity (NHI) Guide