-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Is your feature request related to a problem? Please describe.
Without mandatory MR approvals, an attacker can modify the .gitlab-ci.yml or any script executed by the pipeline (Direct/Indirect PPE), push it, and the pipeline will execute the malicious code before any human review. This is the root cause of two major CI/CD attack vectors:
- Direct PPE: Attacker modifies
.gitlab-ci.ymlon a branch → pipeline runs with secrets - Indirect PPE: Attacker modifies a script called by the pipeline (e.g.,
scripts/run-tests.sh) via a MR → pipeline executes the modified version before approval
The Protection data collector already retrieves MRApprovalRules, MRApprovalSettings, and MRSettings from the GitLab API, but no control currently exploits this data.
Describe the solution you'd like
Add a new control mrApprovalMustBeRequired that verifies:
- MR approvals are required (
approvalsBeforeMerge >= N) - Authors cannot approve their own MR (
mergeRequestsAuthorApproval == false) - Approvals reset on new push (
resetApprovalsOnPush == true) — prevents approved MR from being modified after approval - Committers cannot approve (
mergeRequestsDisableCommittersApproval == true)
Configuration in .plumber.yaml
controls:
mrApprovalMustBeRequired:
enabled: true
# Minimum number of approvals required
minApprovals: 1
# Author must not be able to approve their own MR
preventAuthorApproval: true
# Approvals must reset when new commits are pushed
resetApprovalsOnPush: true
# Committers must not be able to approve
preventCommitterApproval: trueImplementation Hints
These are just ideas. Feel free to change the implementation.
- Data already collected: The
collector/dataCollectionGitlabProtection.goalready fetchesMRApprovalRules,MRApprovalSettings, andMRSettingsvia the GitLab API. This data is passed to controls viaGitlabProtectionData. - New control file: Create
control/controlGitlabProtectionMRApproval.go. - Logic: Compare the project's MR approval settings against the configured requirements. Each sub-check that fails reduces compliance proportionally.
- Compliance calculation: Each enabled sub-check that passes contributes equally. For example, if 4 checks are enabled and 3 pass, compliance = 75%.
- Integration: Wire in
task.goalongside the existingbranchMustBeProtectedcontrol (they share the sameProtectiondata collector).
Files Touched
control/controlGitlabProtectionMRApproval.go(new control)control/types.go(add result field toAnalysisResult)control/task.go(wire the new control, reuse existing Protection data collection)configuration/plumberconfig.go(add config struct and getter).plumber.yaml(add default config section)cmd/analyze.go(add output formatting)
Why It's Valuable
MR approval enforcement is a foundational security control that prevents both Direct and Indirect PPE attacks. The data is already being collected by plumber but not used — this control would unlock that existing investment with minimal effort. It complements branchMustBeProtected by covering the merge request workflow rather than just branch-level protections.