GitLab CI variable masking wrong or protected variable unavailable
Secret appears in plaintext in the job log instead of being masked
Focused incident mode — strips away everything but this runbook.
Symptoms
- Secret appears in plaintext in the job log instead of being masked
- Protected variable is empty when running on a non-protected branch
- Variable value is not masked because it contains characters that prevent masking
GitLab masking requires the variable value to be at least 8 characters and contain no special characters. Values that do not meet these criteria will not be masked even if masked: true is set.
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
CI/CD variable settings
glab api /projects/<PROJECT_ID>/variables --jq '.[] | {key, protected, masked}'Job log output
glab ci trace <PIPELINE_ID> --job <JOB_ID> | grep -E 'key|token|secret' | head -10
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- GitLab requires at least 8 characters and no special characters for masking
- Variable value is 'abc' (too short) or contains newlines
Confirm before fixing
glab api /projects/<PROJECT_ID>/variables/MY_VARCheck the variable masking status
Fix
glab api -X PUT /projects/<PROJECT_ID>/variables/MY_VAR -f value='<NEW_VALUE>' -f masked=true -f protected=trueUpdate the variable with a maskable value
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
glab api /projects/<PROJECT_ID>/variables --jq '.[] | {key, protected, masked}'Check variable metadata
glab api /projects/<PROJECT_ID>/protected_branches --jq '.[].name'List protected branches
glab api -X PUT /projects/<PROJECT_ID>/variables/MY_VAR -f masked=true -f protected=trueUpdate the variable to enable masking and protection
Prevention
- Always set masked: true and protected: true on sensitive CI/CD variables.
- Use values with at least 8 alphanumeric characters for maskable variables.
- Audit variable exposure by grepping job logs for sensitive patterns.
- Rotate variables periodically and delete unused ones.
Related runbooks
Same stack, same failure family — worth a skim.
docker push to registry.gitlab.com fails with 'unauthorized' or 401
Error: Resource not accessible by integration
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.