What the check does
Flags a pipeline that authenticates to AWS, GCP, or Azure with a long-lived static credential. Three signals:- A cloud login action configured with static inputs —
aws-actions/configure-aws-credentialswithaws-access-key-id:,google-github-actions/authwithcredentials_json:,azure/loginwithcreds:orclient-secret:. - A static-credential environment variable or CI variable — a closed set of
names (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,GCP_SA_KEY,GOOGLE_CREDENTIALS,AZURE_CREDENTIALS,AZURE_CLIENT_SECRET,ARM_CLIENT_SECRET, and a few siblings) — or a literalAKIA…access-key id in a value. - A cloud CLI invoked in its static-credential form —
aws configure set aws_access_key_id,gcloud auth activate-service-account,az login --service-principal … -p ….
Why it matters
This is not the “you leaked a key” rule — that is CICD-SEC-6 hardcoded credentials, and it fires on the literal value. This rule fires on a credential stored correctly in secrets, because that is still a credential:- it outlives the job that used it,
- every workflow in the repository can read it,
- and rotating it is a manual task somebody has to remember.
Safe alternative
Grant the job an OIDC token and let the provider mint short-lived credentials.
Then delete the stored credential — leaving it in place keeps the blast
radius the migration was meant to remove.
GitLab CI
The same rule ID fires on.gitlab-ci.yml, driven by variables: blocks and
script: lines rather than actions. The token comes from an id_tokens: block
instead of a permissions: grant:
What does not fire
- A federated login step (
role-to-assume,workload_identity_provider,client-id+tenant-id), on either platform. AWS_SESSION_TOKEN— that is the short-lived half of the pair, and flagging it would advise migrating away from the thing you migrated to.AWS_REGIONand other non-credential configuration.- Commands that merely use an existing identity (
aws s3 sync,gcloud storage cp).