Safeguard
Security Guides

OIDC vs Static Credentials in CI/CD (2026 Guide)

Static secrets in CI are the credential most likely to be stolen — as the CircleCI breach proved. OIDC federation issues short-lived, per-run credentials with nothing to leak. Here is how to make the switch.

Priya Mehta
Security Researcher
6 min read

The credentials most likely to be stolen in your organization are the ones stored in your CI/CD platform, because they are long-lived, highly privileged, and sit in a system every developer and every pipeline can reach. The CircleCI breach of January 2023 is the definitive example: malware on one engineer's laptop stole a session token, gave attackers access to CircleCI's stored secrets, and forced every customer to rotate all of them. Any customer relying on static cloud keys stored as build variables had to assume each one was compromised. OpenID Connect (OIDC) federation removes the target entirely: instead of storing a long-lived secret, the CI platform proves the identity of a specific workflow run to your cloud, which hands back a credential that expires in minutes. There is no static secret to steal, and nothing to rotate. This guide explains the difference and how to migrate.

How static CI credentials fail

A static credential in CI is a durable, high-value secret sitting in a shared system. It leaks the usual ways — printed to a log, exfiltrated by a compromised build dependency, or stolen along with the platform itself, as in the CircleCI case — and because it does not expire, a leak from six months ago may still be valid today. The blast radius is large because CI credentials are typically broad: a key that can deploy to production, push images to a registry, or publish packages. The Shai-Hulud npm worm of September 2025 specifically harvested exactly these credentials from CI environments to propagate. Every one of these failure modes traces back to the same root cause: the credential is long-lived and stored where it can be read.

How OIDC federation works

OIDC replaces the stored secret with a trust relationship. When a workflow runs, the CI platform mints a short-lived, signed identity token (a JWT) describing that specific run — which repository, which branch, which workflow. Your cloud provider is configured to trust that CI platform as an identity provider and to exchange a valid token, matching conditions you set, for temporary credentials. The credentials live only for the job and cannot be replayed afterward, and because the trust is scoped by claims like repository and branch, a token minted for one repo cannot assume another repo's role. Nothing sensitive is ever stored in the CI platform.

Migrating to OIDC, with config

GitHub Actions to AWS — grant the job permission to request the token, then use the official action to assume a role by ARN instead of reading a stored key:

permissions:
  id-token: write   # allow the runner to request an OIDC token
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
          aws-region: us-east-1
      - run: aws s3 sync ./dist s3://my-bucket

On the AWS side, register GitHub as an OIDC identity provider and restrict the role's trust policy to your repository so no other repo can assume it:

# Restrict the trust condition to a specific repo (illustrative)
# "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com

Publishing to npm — as of 2025, npm supports trusted publishing via OIDC, so a GitHub Actions workflow can publish a package with no NPM_TOKEN stored at all, eliminating the exact token-theft vector behind several npm package compromises.

Static credentials vs OIDC

DimensionStatic credentialOIDC federation
LifetimeLong-lived until rotatedMinutes, per job
Stored in CIYes — a theft targetNo secret stored
Rotation neededYes, on a scheduleNone
Blast radius if platform breachedEvery stored key compromisedNothing to steal
ScopingWhatever the key was grantedBound to repo/branch/workflow claims
Setup effortLow initially, ongoing rotation costHigher one-time, near-zero upkeep

How Safeguard's secret scanning helps

Migrating to OIDC only reduces risk if the old static keys actually leave your repositories and CI configs — half-finished migrations leave a dead-but-still-committed AWS_ACCESS_KEY_ID behind. Safeguard's secret scanning finds static CI credentials across your repositories, workflow YAML, and full git history, so you can confirm the switch to OIDC is complete before rotating and deleting the old keys. Griffin AI validates which leftover secrets are still live and ranks them by reach, and developers keep new static tokens from creeping back into pipeline config by running the Safeguard CLI in pre-commit and CI. Because secrets, dependency risk, and misconfigurations surface in one software composition analysis view, you manage CI supply-chain exposure — the same surface the Shai-Hulud worm abused — from a single prioritized queue, and auto-fix can open the pull request that removes a hardcoded credential.

Bring continuous secret and dependency scanning to your pipelines and repositories — get started free or read the documentation.

Frequently Asked Questions

What is OIDC federation in CI/CD, in plain terms?

It is a way for a CI job to prove its identity to your cloud without storing a password. The CI platform issues a short-lived, signed token describing the specific run, and the cloud — configured to trust that platform — exchanges the token for temporary credentials that expire when the job ends. Because nothing durable is stored in CI, there is no static secret to leak or rotate.

Why is OIDC safer than a static access key in CI?

A static key is long-lived and stored in a shared system, so it is a standing target — the CircleCI breach forced every customer to rotate exactly these secrets. OIDC credentials exist only for the duration of a job and are scoped to a specific repository and workflow by claims in the token, so a stolen token is worthless after the run and cannot be used against another repository.

Does OIDC work with every cloud and CI platform?

The major combinations are well supported: GitHub Actions and GitLab CI can federate to AWS, Google Cloud, and Azure, and as of 2025 npm supports OIDC trusted publishing. Some older or self-hosted systems still require static credentials — for those, keep the secret in a proper secrets manager, scope it tightly, and rotate it on a schedule until an OIDC path is available.

How do I confirm my OIDC migration removed the old keys?

Scan your repositories, workflow files, and git history for any remaining static credentials after switching to OIDC. A migration that adds OIDC but leaves the old AWS_ACCESS_KEY_ID committed or configured has not closed the risk. Confirm the static keys are gone, then deactivate and delete them at the provider so a copy that leaked earlier can no longer be used.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.