Cloud login uses a long-lived credential instead of OIDC

ID

oidc_preferred_over_pat

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Family

SCM

Tags

ASVS50:v13.3.1, cicd-sec-06, cicd-security, reachable, security, spvs10-v3.2.1, spvs10-v3.2.2, supply-chain

Description

Does a CI workflow authenticate to a cloud provider with a long-lived stored credential where short-lived federated OIDC is available?

A stored cloud credential — an AWS access key, a GCP service-account key JSON, an Azure service-principal secret — is a standing liability: it lives in your CI secrets, can leak (logs, forks, compromised actions), is rarely rotated, and grants persistent access until someone revokes it. GitHub Actions supports OpenID Connect (OIDC): with permissions: id-token: write the runner mints a short-lived token per run that the cloud exchanges for temporary credentials — no stored secret at all.

This check parses .github/workflows/*.yml and reports a step that calls a known cloud-auth action with a long-lived-credential input:

Cloud Long-lived input (flagged) OIDC alternative

AWS (aws-actions/configure-aws-credentials)

aws-access-key-id / aws-secret-access-key

role-to-assume + permissions: id-token: write

Google Cloud (google-github-actions/auth)

credentials_json

workload_identity_provider + permissions: id-token: write

Azure (azure/login)

creds / client-secret

client-id/tenant-id/subscription-id + permissions: id-token: write

GitHub-Actions only. GitLab (native id_tokens:) and Azure Pipelines (service connections) use different mechanisms and are out of scope here. The finding records whether id-token: write is already granted — if it is, the workflow is usually half-migrated and can drop the stored key.
Example — FAIL
- uses: aws-actions/configure-aws-credentials@v4
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Example — PASS (OIDC)
permissions:
  id-token: write
  contents: read
steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/ci
      aws-region: eu-west-1

Security

Federated OIDC eliminates the most common cloud-credential exposure in CI: a long-lived key sitting in repository/organization secrets. Short-lived tokens are scoped per run and expire automatically, so a leak has a minutes-long blast radius instead of an open-ended one. This is a core CICD-SEC-6 (Insufficient Credential Hygiene) control.

Mitigation / Fix

Migrate the cloud login to OIDC:

  • Add permissions: id-token: write to the job (or workflow).

  • AWS — configure an IAM OIDC identity provider for GitHub and pass role-to-assume instead of access keys. See Configuring OIDC in AWS.

  • Google Cloud — configure Workload Identity Federation and pass workload_identity_provider instead of credentials_json.

  • Azure — configure a federated credential on the app registration and pass client-id/tenant-id/subscription-id instead of creds.

  • Delete the now-unused access-key/secret from CI secrets.

Configuration

This detector has no configurable properties; it matches the well-known cloud-auth actions and their long-lived-credential inputs.