Résumé
ONYEDIKACHI BERNARDCLOUD · DEVSECOPS · AI
RésuméGet in touch
CASE 19BUILD & CI/CD

Pipeline Access Gate Hardening

A protected branch required approval for merge requests, but the policy was not technically enforced. A developer could approve and merge their own changes, reaching the build runner through the pipeline. I traced the bypass and identified the controls to close it.

Status: ASSESSED · VERIFIED

DOMAIN
Build & CI/CD
PLATFORM
GitLab CI/CD
SEVERITY
High
OUTCOME
Access gate bypass confirmed

TOOLS

GitLabGitLab CI/CDGitLab RunnerBashLinuxSSHProtected BranchesMerge RequestsPipeline Access Controls
RESULT
BEFORESelf-approval allowed
AFTERBypass path documented
01

Objective

I set out to assess whether the CI/CD access controls on a protected branch were technically enforced, specifically whether the two-person approval principle could be bypassed by a single developer account.

02

Scenario

A GitLab repository had its main branch marked as protected, and the organisation's policy required independent approval before any merge request could be merged. I wanted to determine whether the platform actually prevented a developer from approving and merging their own code, and what that would mean for the build runner.

03

What I found

branch-protectionSELF APPROVAL
Protected branch:        main
Direct push:             Blocked
Merge-request approval:  Required but not enforced independently
Self-approval:           Allowed
FINDING 01HIGH

Self-approval not technically prevented

The protected main branch blocked direct pushes, but the merge-request approval requirement was not configured to prevent the author from approving their own request. A single developer account could open, approve, and merge a change into main.

runner-accessRUNNER COMPROMISED
Pipeline trigger:        Automatic on merge to main
Runner identity:         gitlab-runner
Runner access:           OS-level shell on build runner
FINDING 02HIGH

Pipeline executed on the main-branch runner

Once the self-approved merge request landed on main, the CI/CD pipeline triggered automatically and ran on the runner assigned to the protected branch. The runner executed the pipeline instructions without any additional gate.

The combination of self-approval and automatic pipeline execution meant a single compromised developer account could run arbitrary code on the protected branch's runner.

04

What I did

  1. Tested branch protection

    I confirmed that direct pushes to main were blocked, so the protection was partially in place.

  2. Tested the approval workflow

    I created a merge request and found that the same account could approve and merge it without independent review.

  3. Traced the pipeline path

    The merged change triggered a pipeline that ran on the main-branch runner, confirming the full path from self-approval to runner access.

  4. Documented the missing enforcement

    The platform's approval settings needed to require a different user from the merge-request author.

EVIDENCE

TEXT
# Approval and execution chain
Step 1:  Developer creates merge request to main
Step 2:  Same developer approves the merge request
Step 3:  Pipeline triggers automatically on merge
Step 4:  Runner executes pipeline as gitlab-runner
05

Validation

The lab verification confirmed runner access after the self-approved merge request triggered the pipeline. The bypass was reproducible with a single developer account.

06

Before and after

CONTROLBEFOREAFTER
Direct push to mainBlockedBlocked (already in place)
Self-approvalAllowedDocumented; enforcement recommended
Independent reviewNot enforcedRecommended: require different approver
Pipeline triggerAutomatic, no gateRecommended: approval gate for protected pipelines
Runner isolationNot assessedRecommended: restricted runner access
07

What I recommend

  1. 01Require merge-request approvals from a user other than the author before merging to protected branches.
  2. 02Set the minimum number of approvals to at least one independent reviewer.
  3. 03Prevent merge-request authors from approving their own requests in the platform settings.
  4. 04Add a manual approval step in the pipeline for deployments to protected environments.
  5. 05Monitor merge and pipeline activity on protected branches for policy bypasses.

“A security policy is only effective when the CI/CD platform technically enforces it. Protecting a branch without enforcing independent approval can still allow a compromised developer account to reach the build runner.”

WHAT I LEARNED

SKILLS IT PROVES

  • CI/CD Security
  • GitLab Security
  • Pipeline Security
  • Access Control
  • Branch Protection
  • Vulnerability Assessment
  • Security Misconfiguration Analysis
  • GitLab Runner Security
  • Least Privilege
  • Separation of Duties
View my labs on GitHub