Rules / GL082
GL082 Managed security scan disabled by CI/CD variable
Severity: warn
OWASP: CICD-SEC-1 – Insufficient Flow Control Mechanisms
What glsec checks
Each GitLab-managed security template gates its jobs on a kill-switch variable:
# from Jobs/SAST.gitlab-ci.yml
rules:
- if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
Set that variable and the scan disappears from the pipeline. glsec flags it in variables: at the top level, under default:, or in a job:
| Variable | Scan removed |
|---|---|
SAST_DISABLED |
SAST (all analyzers) |
SECRET_DETECTION_DISABLED |
Secret detection |
CONTAINER_SCANNING_DISABLED |
Container scanning |
DEPENDENCY_SCANNING_DISABLED |
Dependency scanning |
DAST_DISABLED |
DAST |
DAST_DISABLED_FOR_DEFAULT_BRANCH |
DAST, on the default branch only |
COVFUZZ_DISABLED |
Coverage-guided fuzzing |
API_FUZZING_DISABLED |
API fuzzing |
DAST_API_DISABLED |
DAST API |
Which values count
The templates compare against strings, case-sensitively, so only true and 1 disable anything:
variables:
SAST_DISABLED: "true" # flagged — matches the gate
SAST_DISABLED: "1" # flagged — matches the gate
SAST_DISABLED: true # flagged — YAML boolean, GitLab stringifies it to "true"
SAST_DISABLED: "True" # NOT flagged — "True" != 'true', the scan still runs
SAST_DISABLED: "false" # NOT flagged
The quoted "True" case is worth knowing about in its own right: it reads as a disabled scan but is not one.
Why it matters
This is the quiet way to lose a scan. GL008 catches allow_failure: true on a scan job and GL039 catches a tool silenced with || true, but both need a job to inspect. Here the job is contributed by an include:d template and never materialises — the pipeline is green, the security dashboard has no new findings, and nothing in the YAML looks broken.
A one-line variable is also cheap to add and easy to forget, which is exactly the shape of change that outlives the incident it was added for.
Trigger example
include:
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
variables:
SAST_DISABLED: "true" # warn
SECRET_DETECTION_DISABLED: "1" # warn
build:
stage: build
image: alpine:3.19.1
script:
- make
Safe alternative
Keep the scan and narrow what it looks at, rather than switching it off:
variables:
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp, vendor"
If a scan genuinely does not apply — no supported language, or the scan runs in a different pipeline — suppress it inline with the reason recorded:
variables:
SAST_DISABLED: "true" # glsec:ignore GL082 -- no supported language here, SAST runs in the monorepo pipeline
Notes
- glsec does not resolve
include:, so it cannot confirm the matching template is actually included. The variable is meaningless without it, so the finding is reported wherever the variable is set. LICENSE_SCANNING_DISABLEDandLICENSE_MANAGEMENT_DISABLEDare deliberately absent: the License-Scanning and License-Management templates have been removed from GitLab, so the variables no longer gate anything.CODE_QUALITY_DISABLEDgatesJobs/Code-Quality.gitlab-ci.ymlthe same way, but Code Quality is not a security scan and is out of this rule's scope.SAST_EXCLUDED_ANALYZERSandDS_EXCLUDED_ANALYZERSdisable individual analyzers through the samewhen: nevermechanism. They take analyzer-name lists rather than a boolean and are not covered by this rule.- Only
variables:blocks are inspected. A job that implements the same gate itself (rules: - if: $SECRET_DETECTION_DISABLED) is defining the switch, not flipping it, and is not flagged.
See also
- GL008 —
allow_failure: trueon a security scan job - GL039 — security tool silenced with
|| true - GL067 — analyzer images repointed off the official registry
Documentation for glsec 1.23.0. Source of this page · Rule implementation