You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A workflow that authenticates to a cloud provider with static credentials stored as secrets (AWS access keys, GCP service account JSON, Azure client secrets) carries a long-lived credential into CI. If any step of the job is compromised (malicious action, script injection, leaked log), the attacker gets keys that keep working after the run ends. CI-native OIDC removes that class entirely: the workflow mints a short-lived token per run, nothing to steal that outlives the job.
Suggested by @samrocketman in the CDF Slack: "Credentials must be ephemeral", with STS at deploy time as the example. The static-key pattern is detectable from the workflow YAML.
Proposal
New control: flag jobs that pass long-lived cloud credentials where an OIDC path exists.
Detectable patterns, first pass:
aws-actions/configure-aws-credentials called with aws-access-key-id/aws-secret-access-key inputs instead of role-to-assume (the action supports both, the inputs difference is the signal)
google-github-actions/auth with credentials_json instead of workload_identity_provider
azure/login with creds (secret JSON) instead of federated client-id/tenant-id/subscription-id
generic env pattern: AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY (and equivalents) bound from secrets.* in env: of a job or step
Remediation text: point to the OIDC setup of the matched provider, mention permissions: id-token: write. The fix is well documented by every provider, this control mostly has to name the right doc.
Notes
severity should reflect what the job does: static keys on a deploy/publish job is worse than on a read-only job. Candidate input for the attack-pattern work (Correlate findings into contextual attack patterns #377), a long-lived key inside a job reachable through a weak trigger is exactly a toxic combination
keep an allowlist escape hatch: some providers/on-prem targets have no OIDC support, users need a way to accept a finding permanently
Problem
A workflow that authenticates to a cloud provider with static credentials stored as secrets (AWS access keys, GCP service account JSON, Azure client secrets) carries a long-lived credential into CI. If any step of the job is compromised (malicious action, script injection, leaked log), the attacker gets keys that keep working after the run ends. CI-native OIDC removes that class entirely: the workflow mints a short-lived token per run, nothing to steal that outlives the job.
Suggested by @samrocketman in the CDF Slack: "Credentials must be ephemeral", with STS at deploy time as the example. The static-key pattern is detectable from the workflow YAML.
Proposal
New control: flag jobs that pass long-lived cloud credentials where an OIDC path exists.
Detectable patterns, first pass:
aws-actions/configure-aws-credentialscalled withaws-access-key-id/aws-secret-access-keyinputs instead ofrole-to-assume(the action supports both, the inputs difference is the signal)google-github-actions/authwithcredentials_jsoninstead ofworkload_identity_providerazure/loginwithcreds(secret JSON) instead of federated client-id/tenant-id/subscription-idAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY(and equivalents) bound fromsecrets.*inenv:of a job or stepRemediation text: point to the OIDC setup of the matched provider, mention
permissions: id-token: write. The fix is well documented by every provider, this control mostly has to name the right doc.Notes