highIntermediateSymptom-first#secret#masked#protected#variable

GitLab CI variable masking wrong or protected variable unavailable

Secret appears in plaintext in the job log instead of being masked

Likely source:securityconfiguration

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_VAR
READ

Check the variable masking status

Fix

glab api -X PUT /projects/<PROJECT_ID>/variables/MY_VAR -f value='<NEW_VALUE>' -f masked=true -f protected=true
CHANGE

Update 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.

1
glab api /projects/<PROJECT_ID>/variables --jq '.[] | {key, protected, masked}'
READ

Check variable metadata

2
glab api /projects/<PROJECT_ID>/protected_branches --jq '.[].name'
READ

List protected branches

3
glab api -X PUT /projects/<PROJECT_ID>/variables/MY_VAR -f masked=true -f protected=true
CHANGE

Update 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.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.