VNX-SEC-020: GitLab access token
Reports hardcoded GitLab tokens (glpat-, gldt-, glrt-, glrtr-, glcbt-, gloas-, glptt-, glagent-, glft-, glimt-, glffct-, glsoat-) with real-token entropy. CI variable references, prefix and regex validation code, placeholders and test paths are not reported.
| Field | Value |
|---|---|
| Rule ID | VNX-SEC-020 |
| Severity | Critical |
| SARIF level | error |
| Kind | secrets |
| Languages | Any file |
| CWE | CWE-798 |
| CAPEC | CAPEC-191 |
| ATT&CK | T1552.001 |
| CWSS vector | CWSS:1.0/TI:C/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:C/DI:H/EX:H/EC:N/P:W |
| Tags | secrets gitlab credentials |
| Source | internal/sast/rules/vnx-sec-020.rego |
Overview
This rule specifically targets GitLab personal access tokens (PATs), project access tokens, and group access tokens with the glpat- prefix pattern glpat-[A-Za-z0-9\-_]{20,}. While VNX-SEC-004 detects both GitHub and GitLab tokens, this rule focuses exclusively on the GitLab PAT format and provides more targeted guidance. GitLab tokens with broad scopes (api, write_repository, sudo) grant extensive control over repositories, CI/CD pipelines, group settings, and on self-managed instances, potentially the entire GitLab installation.
Why This Matters
GitLab access tokens can carry any combination of the following scopes: api (full API access), read_api, read_user, read_repository, write_repository, read_registry, write_registry, sudo (admin impersonation), and create_runner. A token with api scope is effectively a complete set of the token owner’s permissions, including access to every project, group, and organization-level setting they can reach.
GitLab project access tokens and group access tokens can be configured with maintainer or owner roles, meaning they can be used to modify CI/CD pipeline definitions, a direct path to supply chain compromise. On self-managed GitLab instances with the sudo scope, a leaked admin token grants complete control over all users, projects, and system settings.
GitLab has built-in token detection but detection alone is insufficient, the token must be revoked and replaced.
What Gets Flagged
# FLAGGED: GitLab PAT hardcoded
import gitlab
gl = gitlab.Gitlab('https://gitlab.com', private_token='glpat-EXAMPLE_REDACTED')
projects = gl.projects.list()
# FLAGGED: token in curl command for CI script
curl --header "PRIVATE-TOKEN: glpat-EXAMPLE_REDACTED" \
"https://gitlab.com/api/v4/projects/123/pipelines"
# FLAGGED: token in .gitlab-ci.yml
variables:
DEPLOY_TOKEN: "glpat-EXAMPLE_REDACTED"
Remediation
-
Revoke the token immediately. In GitLab go to User Settings → Access Tokens → find the token → Revoke. For project tokens: Project → Settings → Access Tokens → Revoke. For group tokens: Group → Settings → Access Tokens → Revoke.
-
Review GitLab audit events for API activity during the exposure period. Admins can access this at Admin Area → Monitoring → Audit Events. Project maintainers can view project-level audit events at Project → Security & Compliance → Audit events.
-
For CI/CD pipelines, use the built-in
CI_JOB_TOKENinstead of a personal access token.CI_JOB_TOKENis automatically injected into each job, scoped to the current project, and expires when the job completes:
# SAFE: use CI_JOB_TOKEN in .gitlab-ci.yml
deploy:
script:
- curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \
"https://gitlab.com/api/v4/projects/123/packages/npm/"
- For cross-project access in CI, configure CI_JOB_TOKEN allowlists rather than sharing a PAT:
# SAFE: trigger downstream pipeline with CI_JOB_TOKEN
trigger:
project: group/downstream-project
strategy: depend
- For automation outside CI, create a dedicated project access token** or group access token with the minimum required scope and expiration date, then store it in GitLab CI/CD variables (masked and protected) or your secrets manager:
# SAFE: load GitLab token from environment
import gitlab
import os
gl = gitlab.Gitlab('https://gitlab.com', private_token=os.environ['GITLAB_TOKEN'])
-
Configure token expiration. GitLab now requires expiration dates on PATs. Set the shortest expiration that is operationally feasible and implement automated rotation.
-
Scan git history for any exposed tokens:
gitleaks detect --source . --verbose
git filter-repo --replace-text <(echo 'glpat-xxxx==>REDACTED_GITLAB_TOKEN')
References
- CWE-798: Use of Hard-coded Credentials
- GitLab: Personal access tokens
- GitLab: CI/CD job token
- GitLab: Project access tokens
- GitLab: Push rules for secret detection
- MITRE ATT&CK T1552.001 – Credentials In Files
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-sec-020
// nosec vnx-sec-020
Or record an ignore rule: vulnetix ignore add --rule vnx-sec-020 --reason "...". See Suppressing findings.