Security gap: failed dependency scanner with allow_failure:true bypasses approval policy
Summary
When a Scan Execution Policy (SEP) or Pipeline Execution Policy (PEP) injects multiple security scanners into a pipeline, and one scanner (e.g. gemnasium-maven-dependency_scanning) fails with exit code 1 producing no report artifact, while other scanners (e.g. secret_detection) succeed and produce reports — the MR Approval Policy with fallback_behavior: fail: closed does not block the merge request. The MR remains "Ready to merge" despite having zero dependency scanning coverage.
Steps to reproduce
- Create a group with a compliance framework (e.g. id: 1)
- Create a security policy project linked to the group with the following
policy.yml:
---
experiments:
ensure_pipeline_policy_pre_succeeds:
enabled: true
approval_policy:
- name: mic_vulnerability_approval_policy
enabled: true
rules:
- type: scan_finding
scanners:
- dependency_scanning
vulnerabilities_allowed: 0
severity_levels:
- critical
- high
vulnerability_states:
- new_needs_triage
branch_type: default
vulnerability_attributes:
fix_available: true
- type: scan_finding
scanners:
- sast
- secret_detection
vulnerabilities_allowed: 0
severity_levels:
- critical
- high
vulnerability_states:
- new_needs_triage
branch_type: default
actions:
- type: require_approval
approvals_required: 1
role_approvers:
- maintainer
approval_settings:
require_password_to_approve: false
fallback_behavior:
fail: closed
policy_tuning:
unblock_rules_using_execution_policies: true
scan_execution_policy:
- name: enforce-dep-scan
enabled: true
rules:
- type: pipeline
branches:
- "*"
actions:
- scan: dependency_scanning
variables:
AST_ENABLE_MR_PIPELINES: "true"
- scan: sast
variables:
AST_ENABLE_MR_PIPELINES: "true"
- scan: secret_detection
variables:
AST_ENABLE_MR_PIPELINES: "true"
policy_scope:
compliance_frameworks:
- id: 1- Create a test project with the compliance framework applied, simple .gitlab-ci.yml and a working
pom.xml.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test-app</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
</project>
- Update pom.xml in a separate branch with a malfunctioned xml which causes
gemnasium-mavento fail:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test-app</artifactId>
<version>1.0.0</version>
<repositories>
<repository>
<id>broken-repo</id>
<url>https://repo.does-not-exist.invalid/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.nonexistent</groupId>
<artifactId>fake-artifact</artifactId>
<version>9.9.9</version>
</dependency>
</dependencies>
</project>- Open a merge request targeting the default branch
- Observe the pipeline —
gemnasium-maven-dependency_scanningfails with exit code 1, nogl-dependency-scanning-report.jsonproduced;secret_detectionsucceeds - Observe the MR — it shows "Ready to merge" despite the failed dependency scanner
Example Project
Reproduced on a self-managed GitLab 19.0.1-ee instance. Example project not publicly available
What is the current bug behavior?
gemnasium-maven-dependency_scanningfails with exit code 1- No
gl-dependency-scanning-report.jsonartifact is produced - Pipeline status: passed with warnings (due to
allow_failure: truehardcoded in the scanner template) fallback_behavior: fail: closeddoes not trigger- MR approval policy reports: "Security policy violations have been resolved"
- MR status: Ready to merge — with zero dependency scanning coverage
Pipeline job output:
$ /analyzer run
[INFO] [gemnasium-maven] ▶ GitLab gemnasium-maven analyzer v6.6.1
exit status 1
WARNING: gl-dependency-scanning-report.json: no matching files.
ERROR: No files to upload
ERROR: Job failed: exit code 1What is the expected correct behavior?
When a scanner configured in a Scan Execution Policy or Pipeline Execution Policy fails and produces no report artifact, fallback_behavior: fail: closed should trigger and block the MR with:
"Pipeline configuration error: Security reports required by policy
<policy_name>could not be found."
This correctly occurs when only the failing scanner runs. The bug manifests specifically when multiple scanners run and at least one succeeds — the policy engine evaluates the successful reports and passes, silently ignoring the missing report from the failed scanner.
Relevant logs and/or screenshots
Pipeline evidence (from customer):
{
"failed_job": {
"name": "gemnasium-maven-dependency_scanning",
"status": "failed",
"allow_failure": true,
"error": "exit status 1 — no gl-dependency-scanning-report.json produced",
"artifacts_produced": "NONE"
},
"security_policy": {
"name": "mic_vulnerability_approval_policy",
"blocks_merge": false,
"reason": "No vulnerability findings to evaluate (no report uploaded)"
}
}Confirmed reproduction matrix:
| Configuration | Dependency scan | Other scans | MR blocked? |
|---|---|---|---|
| SEP, single scanner only | Failed, no report | N/A | |
| SEP, multiple scanners | Failed, no report | Passed | |
| PEP, multiple scanners | Failed, no report | Passed | |
| SEP + PEP combined | Failed, no report | Passed |
Toggles tested that do NOT fix the issue:
unblock_rules_using_execution_policies: false— still mergeableexperiments: ensure_pipeline_policy_pre_exceeds: enabled: true— still mergeable- Removing
vulnerability_attributes: fix_available: true— still mergeable - Splitting
dependency_scanninginto its own separate rule — still mergeable
Workaround
The following workaround was confirmed to block the MR when the dependency scanner fails:
Requires both of the following:
-
Enable "All security policy pipelines must succeed" in the project settings (Settings > Merge requests > All security policy pipelines must succeed)
-
Use a Pipeline Execution Policy (not SEP) and override
allow_failure: falseongemnasium-maven-dependency_scanningin the injected CI file:
include:
- template: Jobs/Dependency-Scanning.latest.gitlab-ci.yml
- template: Jobs/SAST.latest.gitlab-ci.yml
- template: Jobs/Secret-Detection.latest.gitlab-ci.yml
gemnasium-maven-dependency_scanning:
allow_failure: falseLimitation: This workaround requires switching from SEP to PEP for scan injection, and enabling the project-level setting on all affected projects. It does not fix the underlying bug in fallback_behavior: fail: closed.
Output of checks
- GitLab version: 19.0.1-ee (self-managed, also reported on GitLab Dedicated)
- Offering: GitLab Dedicated + Self-Managed
- Plan: Ultimate
Results of GitLab environment info
Expand for output related to GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: `sudo gitlab-rake gitlab:env:info`) (For installations from source run and paste the output of: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
Results of GitLab application Check
Expand for output related to the GitLab application check
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:check SANITIZE=true)(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)(we will only investigate if the tests are passing)
Possible fixes
The policy engine's fallback_behavior: fail: closed logic likely evaluates whether any required scan report is present rather than checking that all configured scanners produced reports. When at least one scanner succeeds, the fallback is not triggered even if other configured scanners failed with no report.
The fix should ensure that fallback_behavior: fail: closed triggers independently per scanner rule — if a scanner configured in the policy failed and produced no report, that rule should be treated as a violation regardless of other scanners' outcomes.
Patch release information for backports
If the bug fix needs to be backported in a patch release to a version under the maintenance policy, please follow the steps on the patch release runbook for GitLab engineers.
Refer to the internal "Release Information" dashboard for information about the next patch release, including the targeted versions, expected release date, and current status.
High-severity bug remediation
To remediate high-severity issues requiring an internal release for single-tenant SaaS instances, refer to the internal release process for engineers.