glsec

Rules / GL006

GL006 Hardcoded secrets in variables: block

Severity: error
OWASP: CICD-SEC-6 – Insufficient Credential Hygiene

What glsec checks

glsec scans all variables: blocks (global, default:, and per-job) for scalar values that match known secret patterns:

Pattern Example match
GitLab PAT glpat-… (20+ chars)
GitLab runner token glrt-…
GitLab deploy token gldt-…
GitLab CI job token glcbt-…
AWS access key AKIA… / ASIA… / AGPA… / AIDA… / AROA… / AIPA… / ANPA… / ANVA… (16 chars)
PEM private key header -----BEGIN … PRIVATE KEY
GitHub PAT ghp_… (36+ chars)
GitHub fine-grained PAT github_pat_… (82+ chars)
GitHub App installation token ghs_… (fixed-length and ghs_<appid>_<jwt> forms)
GitHub OAuth / user / refresh token ghu_… / gho_… / ghr_… (36+ chars)
Slack token xoxb-… / xoxp-… / xoxa-… / xoxs-… / xoxr-…
Anthropic API key sk-ant-…
OpenRouter API key sk-or-v1-…
OpenAI API key sk-… containing the T3BlbkFJ watermark
OpenAI project API key sk-proj-… containing the T3BlbkFJ watermark
OpenAI service/admin API key sk-svcacct-… / sk-admin-… / sk-service-… containing the T3BlbkFJ watermark
OpenAI realtime client secret ek_… (32+ hex chars)
PyPI upload token pypi-AgEIcHlwaS5vcmc…
npm access token npm_… (36 chars)
Stripe secret key sk_test_… / sk_live_…
HuggingFace token hf_… (34–40 chars)
GCP service account key JSON value containing "type": "service_account"
Databricks token dapi… (32 hex chars)
Doppler token dp.pt.…
SendGrid API key SG.<22>.<43>
PlanetScale token pscale_pw_… / pscale_tkn_…
Postman API key PMAK-…
RubyGems API key rubygems_… (48 hex chars)
New Relic API key NRAK-…
Shopify access token shpss_… / shpat_… / shpca_… / shppa_…
Brevo (Sendinblue) API key xkeysib-…
age secret key AGE-SECRET-KEY-1…
Clojars deploy token CLOJARS_… (60 chars)
Dynatrace token dt0c01.<24>.<64>
Duffel API token duffel_test_… / duffel_live_…
Frame.io token fio-u-… (64 chars)
Terraform Cloud token …atlasv1.…
Linear API key lin_api_… (40 chars)
New Relic browser key NRJS-… (19 hex chars)
Pulumi access token pul-… (40 hex chars)
Shippo API token shippo_live_… / shippo_test_…
Slack webhook URL https://hooks.slack.com/services/…
Alibaba access key ID LTAI…
Private Packagist token packagist_…
Adobe client secret p8e-… (32 chars)
Flutterwave secret key FLWSECK_TEST-… / FLWPUBK_TEST-…
Cloudflare API token cfut_… / cfat_… (40 chars + 8 hex checksum)
Cloudflare Origin CA key v1.0-<24 hex>-<146 hex>
Bitbucket Data Center token BBDC-… (32+ chars)
NuGet API key oy2… (46 chars, base32, case-insensitive)

Values that are variable references (starting with $) are ignored. Obvious documentation placeholders are also skipped: a matched value is ignored when it contains example, placeholder, changeme, redacted, or your-token-here (case-insensitive) — for instance AKIAIOSFODNN7EXAMPLE or glpat-your-token-here.

Trigger example

variables:
  AWS_SECRET_ACCESS_KEY: "AKIAIOSFODNN7EXAMPLE"
  DEPLOY_TOKEN: "glpat-xxxxxxxxxxxxxxxxxxxx"

deploy:
  script:
    - aws s3 sync dist/ s3://my-bucket/

Safe alternative

Store secrets in GitLab CI/CD Variables (project Settings → CI/CD → Variables). Mark them as Masked so they are redacted in job logs, and optionally as Protected to restrict access to protected branches.

Reference them by name without embedding the value in the file:

variables:
  # References a masked CI/CD variable — no secret stored in the repo
  AWS_SECRET_ACCESS_KEY: "$AWS_SECRET_ACCESS_KEY"

deploy:
  script:
    - aws s3 sync dist/ s3://my-bucket/

Why this matters

Variables in .gitlab-ci.yml are committed to git history and visible to every user with repository read access. A secret stored here:

The only safe remediation after accidental exposure is to immediately rotate the credential.

Documentation for glsec 1.23.0. Source of this page · Rule implementation