Almost every account in a software delivery chain can change what ships to production, yet source control, CI servers, registries and deployment tools are rarely governed with the same rigour as the corporate directory. CICD-SEC-2, Inadequate Identity and Access Management, is the second risk in the OWASP Top 10 CI/CD Security Risks. It covers the human and programmatic identities spread across the engineering ecosystem and the ways they become over-permissive, stale, local, external, self-registered or shared. This guide explains what OWASP actually says, turns its nine recommendations into an implementation plan with concrete platform settings, and maps the risk to NIST, CIS, ISO and the OWASP Non-Human Identity Top 10. It is written for platform engineers, AppSec and IAM teams who own the identity side of the pipeline.
Key takeaways
- It is an identity governance problem, not a tooling gap. OWASP defines the risk as the difficulty of managing the vast number of human and programmatic identities across systems from source control to deployment.
- Machine identities outnumber people. Personal access tokens, OAuth and marketplace apps, plugins, SSH keys and CI tokens each have their own provisioning path and permission model, and each needs an owner and a lifecycle.
- Federate first. Local accounts on SCM, CI and registry systems escape password, MFA, lockout and leaver policies; central IdP federation is the single highest-leverage control.
- Default permissions should be none. Self-registration, broad base permissions and auto-assigned groups turned single account compromises into build server takeovers at Stack Overflow and exposed source code at self-hosted GitLab instances.
- Measure granted against used. OWASP asks for a continuous map of each identity's provider, granted permissions and permissions actually used; the gap is your reduction backlog.
What it is and who it applies to
The OWASP Top 10 CI/CD Security Risks was written by Daniel Krivelevich and Omer Gil, then of Cider Security, and reviewed by practitioners from organisations including Atlassian, Netflix, Databricks and Rapid7. Each risk follows the same structure: definition, description, impact, recommendations and references. CICD-SEC-2 states that poorly managed identities, both human and programmatic, increase both the likelihood and the extent of damage when one is compromised. OWASP's impact statement is blunt: with hundreds or thousands of identities and common over-permissive accounts, compromising nearly any user account on any system could grant powerful capabilities and act as a route into production.
The risk applies to every system that moves code or artefacts towards production:
- Source control (SCM): GitHub, GitLab, Bitbucket, Azure Repos, including organisation owners, repository admins, deploy keys and installed apps.
- CI and CD systems: Jenkins, TeamCity, GitHub Actions, GitLab CI, CircleCI, Argo CD and similar, including their service accounts and runner credentials.
- Artefact and package registries: container registries, Artifactory or Nexus, npm and PyPI publishing accounts.
- Deployment targets: cloud roles, Kubernetes service accounts and infrastructure-as-code backends assumed by pipelines.
It sits next to two sibling risks that are easy to confuse with it. CICD-SEC-5 (Insufficient PBAC) concerns what the pipeline execution context can reach, and CICD-SEC-6 (Insufficient Credential Hygiene) concerns how secrets are stored and rotated. CICD-SEC-2 is about the accounts themselves: who and what exists, who approved it, what it may do and when it goes away. See the Top 10 CI/CD Security Risks for the full list.
Structure and key requirements
OWASP describes six concern categories and nine recommendations. The table pairs them so each problem has an owner-ready control and a test.
| OWASP concern | What it looks like | OWASP recommendation | How to test it |
|---|---|---|---|
| Overly permissive identities | Engineers and apps with admin or write on every repository; tokens with all scopes | Map granted versus used permissions; remove permissions not needed for ongoing work | Count identities with org-owner or admin rights; compare with role need |
| Stale identities | Leavers and retired systems still holding SCM and CI accounts or tokens | Set an inactivity period and disable or remove identities beyond it | Accounts and tokens with no activity in the agreed window |
| Local identities | Jenkins or self-hosted GitLab users not federated with the IdP | Avoid local accounts; manage identities centrally in an IdP; align any remaining local accounts to policy | Local account count per system; local accounts without MFA |
| External identities | Personal email domains on SCM; outside collaborators with long-lived access | Block non-organisation domains; map external collaborators; grant access with an expiry date | Members with non-corporate verified emails; collaborators with no end date |
| Self-registered identities | Anyone with a valid domain address can sign up and gets a default role | Disallow self-registration; grant permissions as needed; no base permissions for all users or large auto-populated groups | Sign-up setting state; default role for new users |
| Shared identities | One "build" account used by people and pipelines; shared deploy keys | Avoid shared accounts; create dedicated accounts per context with exactly the permissions required | Interactive logins on service accounts; one credential used from many sources |
OWASP's own references show the pattern in practice. In the Stack Overflow incident, a long-standing TeamCity misconfiguration made newly created users administrators, so a stolen service account login became build server admin and then a path to production databases. Stack Overflow's remediation included removing default group assignments in TeamCity. OWASP also cites the Mercedes-Benz source code leak from an internet-facing GitLab server open to self-registration, a New York state GitLab server where anyone could register and reach stored secrets, and the 2018 Gentoo GitHub compromise via a maintainer's password.
Identity and NHI requirements
CICD-SEC-2 is core non-human identity territory. OWASP names personal access tokens, marketplace applications, OAuth applications, plugins and SSH keys as access methods, each with its own provisioning and authorisation model. The table sets out the main pipeline NHI types and the preferred pattern for each.
| Pipeline identity | Typical weakness | Preferred pattern | Related OWASP NHI risk |
|---|---|---|---|
| Personal access token used by automation | Tied to a person, broad scopes, long or no expiry; leaves with the person or survives them | Replace with an app or workload identity; if kept, fine-grained, single-repository, short expiry, admin approved | NHI10 Human Use of NHI, NHI7 Long-Lived Secrets |
| OAuth app authorised by a user | Acts as the user across every repository the user can reach; tokens do not expire until revoked | App with fine-grained permissions installed on selected repositories | NHI5 Overprivileged NHI, NHI3 Vulnerable Third-Party NHI |
| CI job token (for example GITHUB_TOKEN) | Default permissions broader than the job needs; readable by every action in the job | Explicit permissions block per workflow or job, read-only default | NHI5 Overprivileged NHI |
| Cloud credentials for deployment | Static keys stored as CI secrets, shared across environments | OIDC federation with trust conditions on repository, branch and environment | NHI7 Long-Lived Secrets, NHI8 Environment Isolation |
| Deploy keys and runner SSH keys | Write-enabled, never rotated, reused across repositories | Read-only by default, one key per repository, inventory with owner | NHI9 NHI Reuse, NHI1 Improper Offboarding |
| Shared "build" or "release" bot user | Used interactively by staff, no accountability, often excluded from MFA | Dedicated identity per pipeline context; humans use their own federated accounts | NHI10 Human Use of NHI, NHI4 Insecure Authentication |
Platform features now make the preferred patterns practical. GitHub's documentation states that an action can access the GITHUB_TOKEN through the github.token context even when the workflow does not pass it, which is why the permissions key should set least privilege for every workflow. GitHub Apps use fine-grained permissions, can be limited to selected repositories, use short-lived tokens, and remain installed when the person who installed them leaves, unlike OAuth apps, whose tokens do not expire until revoked. With OIDC, each job receives a JWT that the cloud provider validates against the subject and other claims in its trust policy before issuing a short-lived token valid only for that job. GitHub also notes that Dependabot can use OIDC to authenticate to private registries instead of stored credentials.
For the deeper identity patterns, see the CI/CD Pipeline Identity Security Guide, the Workload Identity Federation Guide and the OWASP NHI Top 10 NHI5 Overprivileged NHI Guide.
Implementation steps
Sequence matters: inventory before removal, federation before enforcement, and a pilot before organisation-wide policy. Each step names the rollback.
- Build the identity map (weeks 1 to 4). For every SCM, CI, registry and deployment system, export human accounts, outside collaborators, apps and OAuth grants, tokens, deploy keys, SSH keys and service accounts. For each record the identity provider, granted permissions, last activity and owner. OWASP explicitly asks that all methods of programmatic access are covered. See the Service Account Inventory Template.
- Close the front door (weeks 2 to 6). Disable self-registration on self-hosted systems. On GitLab Self-Managed, "Allow new user accounts" is enabled by default and should be turned off, or at least "Require admin approval for new user accounts" kept on with a domain allowlist. Set the default role for new users to none or read.
- Federate and enforce MFA (weeks 4 to 12). Connect every system to the IdP with SAML or OIDC. On GitHub Enterprise Cloud, test SAML SSO, then enforce it; enforcement removes members, including bots and service accounts, that have not authenticated via the IdP, so register machine identities first. Require two-factor authentication for the organisation; outside collaborators without it are removed. Rollback: removed users who rejoin within three months have access restored, so keep an approved list ready.
- Reduce base and standing permissions (weeks 6 to 16). Set organisation base permission to none or read; base permissions apply to all members but not to outside collaborators, and internal repositories keep a minimum of read. Move access to teams mapped to IdP groups. Pilot on one business unit first and keep an exception queue open for a fortnight.
- Govern tokens and apps (weeks 8 to 20). Restrict classic PATs at organisation level, require administrator approval for fine-grained PATs (GitHub's default) and set a maximum lifetime shorter than the 366 day default. Classic tokens have no expiry requirement, which is the main reason to restrict them. Replace OAuth apps and bot users with GitHub Apps installed on selected repositories. Setting a lifetime policy blocks non-compliant tokens from the organisation but does not revoke them, so communicate before switching it on.
- Swap static cloud keys for federation (weeks 10 to 24). Configure OIDC trust per repository and environment, add
id-token: writeonly to jobs that deploy, then delete the stored keys. Keep the old keys disabled, not deleted, for one release cycle as a rollback. - Automate the lifecycle (ongoing). Drive joiners, movers and leavers from HR and the IdP using SCIM where supported. Set a stale period, for example 90 days for humans and 30 days for unused tokens, and disable automatically. Give every external collaborator and every token an expiry date. See the Joiner-Mover-Leaver Guide.
Decision guidance
- GitHub App or fine-grained PAT: choose an app for any automation that outlives a person or touches more than one repository; a fine-grained PAT is acceptable for a short, individual task with a short expiry.
- Enterprise Managed Users or SAML-linked personal accounts: managed users give full lifecycle control and block personal-domain identities by design; SAML linking is easier where developers contribute to open source from the same account. Larger regulated organisations usually justify managed users.
- Small teams: if there is no IdP for every tool, start with organisation 2FA, base permission none, PAT restrictions and quarterly manual reviews. These four settings cover most of OWASP's list.
- Large estates: prioritise identity data aggregation across tools, because manual reviews do not scale past a few hundred repositories; feed the inventory into your IGA or NHI management platform.
Evidence and assessment
Assessors and internal audit will ask for proof that the controls run, not just that they are configured. Collect the following and log the signals that show drift.
| Evidence item | Source | What good looks like |
|---|---|---|
| Identity inventory with owner and last use | SCM, CI and registry exports or an NHI platform | Every identity has an owner; no unknown machine identities |
| SSO and 2FA enforcement state | Organisation security settings, IdP application assignments | Enforced on all systems; local accounts documented as exceptions |
| Base permission and default role settings | Organisation settings, self-hosted admin settings | None or read; self-registration off |
| Token policy | PAT policy pages, app installation lists | Classic tokens restricted; approval and maximum lifetime set |
| Access review records | IGA campaigns or signed review exports | Quarterly for privileged roles, with revocations actioned |
| Audit log retention and alerts | SIEM | Alerts on new admins, new tokens, new apps, member additions outside IdP |
Detection signals: new organisation owners or repository admins; members added outside IdP group sync; token creation or app installation by unusual users; interactive sign-ins by service accounts; activity from identities past their stale threshold; and OIDC token requests from unexpected repositories or branches. ATT&CK techniques to tune for include T1078 Valid Accounts, T1078.004 Cloud Accounts, T1136 Create Account, T1098.001 Additional Cloud Credentials, T1528 Steal Application Access Token and T1213.003 Code Repositories.
Metrics:
- Federation coverage: percentage of CI/CD systems and accounts authenticated via the IdP (target 100 percent of humans).
- Standing admin ratio: organisation and repository admins as a share of all members, tracked downwards.
- Stale identity count: human and machine identities beyond the inactivity threshold, target zero older than one review cycle.
- Static credential share: deployments using stored cloud keys versus OIDC federation.
- Unused permission ratio: granted permissions never exercised in 90 days, from the granted versus used map.
- External identity expiry: percentage of outside collaborators and tokens with an end date.
Mapping to other frameworks
| Framework | Relevant items | How CICD-SEC-2 maps |
|---|---|---|
| NIST SP 800-53 Rev. 5 | AC-2, AC-2(1), AC-2(3), AC-6, AC-6(5), AC-6(7), IA-2(1), IA-4, IA-5, IA-8, IA-9, PS-4 | Account lifecycle and automated management, disabling inactive accounts, least privilege and privilege review, MFA, non-organisational users (external collaborators), service identification, leaver handling |
| NIST CSF 2.0 | PR.AA-01, PR.AA-02, PR.AA-03, PR.AA-05, DE.CM-03 | Identities and credentials managed, proofed and authenticated; permissions defined and reviewed; activity monitored |
| CIS Controls v8.1 | 5.1, 5.3, 6.1, 6.2, 6.5, 6.7, 6.8 | Account inventory, disabling dormant accounts, access granting and revoking, MFA for administrative access, centralised access control, role-based access |
| ISO/IEC 27001:2022 Annex A | 5.15, 5.16, 5.17, 5.18, 8.2, 8.5 | Access control, identity management, authentication information, access rights, privileged access, secure authentication |
| OWASP NHI Top 10 | NHI1, NHI5, NHI7, NHI9, NHI10 | Offboarding, overprivilege, long-lived secrets, reuse and human use of machine identities |
| MITRE ATT&CK v20 | T1078, T1078.004, T1136, T1098.001, T1528, T1213.003 | Techniques an attacker uses once identity governance fails |
For the machine identity angle, see the OWASP NHI Top 10 NHI1 Improper Offboarding Guide, the OWASP NHI Top 10 NHI10 Human Use of NHI Guide and the OWASP NHI Top 10 NHI7 Long-Lived Secrets Guide.
Common pitfalls
- Strong MFA, weak session and role design. In the CircleCI Breach, malware stole an engineer's 2FA-backed SSO session, and because that engineer could generate production access tokens, the attacker reached customer secrets. MFA at login does not limit what a standing role can do afterwards.
- Classic tokens left unrestricted. The Fake Dependabot Commits campaign used stolen personal access tokens to push commits disguised as dependabot[bot] that added a secret-stealing workflow. Restricting classic tokens and requiring review of workflow changes would have narrowed it.
- Enforcing SSO before registering bots. Turning on SAML enforcement without mapping service accounts removes them and breaks pipelines, which leads teams to roll back and leave enforcement off for good.
- Default roles above none. Stack Overflow's TeamCity gave new users administrator rights; any similar default on Jenkins, GitLab or a registry turns a single account into control of the build.
- Reviewing people but not machines. Access reviews that cover human members but skip apps, OAuth grants, deploy keys and tokens leave the largest population ungoverned. See the Access Reviews Guide.
- One shared automation user for everything. It defeats attribution in an investigation, accumulates permissions over years and is usually exempt from MFA.
Practitioner checklist
- Inventory every human and programmatic identity across SCM, CI, registries and deployment targets, with provider, owner, granted and used permissions.
- Disable self-registration and set default and base permissions to none or read on every system.
- Federate all CI/CD systems with the IdP and enforce SSO and 2FA, after registering machine identities.
- Restrict classic personal access tokens; require approval and a maximum lifetime for fine-grained tokens.
- Replace OAuth apps and shared bot users with apps or workload identities scoped to selected repositories.
- Set explicit least-privilege
permissionsfor CI job tokens and use OIDC federation for cloud deployment. - Block non-organisation email domains and give every external collaborator an expiry date.
- Disable identities automatically after a defined inactivity period and on leaver events.
- Alert on new admins, new tokens, new app installs and service account interactive sign-ins.
- Run quarterly reviews that include apps, keys and tokens, not only people.
Standards and references
- OWASP: CICD-SEC-2 Inadequate Identity and Access Management
- OWASP: Top 10 CI/CD Security Risks
- NIST: SP 800-53 Rev. 5
- NIST: Cybersecurity Framework 2.0
- GitHub Docs: OpenID Connect
- GitHub Docs: Setting a personal access token policy for your organization
- GitLab Docs: Sign-up restrictions
- Stack Overflow: A deeper dive into our May 2019 security incident
Related NHI Mgmt Group resources: CI/CD Pipeline Identity Security Guide · CI/CD Security Guide · OWASP CI/CD Top 10 CICD-SEC-6 Insufficient Credential Hygiene Guide · OWASP NHI Top 10 NHI5 Overprivileged NHI Guide