Privilege Escalation Vulnerability

Privilege Escalation Vulnerability in CI/CD pipelines

Most teams picture a privilege escalation vulnerability as a kernel bug or a misused sudo on a production server. In 2026, the more dangerous version lives somewhere else: in the pipeline that builds and ships your code. A CI/CD job routinely holds write access to your repositories, tokens for your package registries and credentials for your cloud. An attacker who gets code running inside that job doesn’t need to escalate much. The pipeline has already done it for them.

This guide explains what a privilege escalation vulnerability looks like in CI/CD pipelines and containers, walks through the most common paths attackers use, and shows how to close each one.

TL;DR: privilege escalation vulnerability in CI/CD pipelines

In a pipeline, the attacker often doesn't need to escalate privileges. The pipeline already has them. A privilege escalation vulnerability in CI/CD is usually a permission drawn wider than the job needs, waiting for untrusted code to run inside it.

  • Pipelines are privileged by design. They read source code, hold secrets, publish artifacts and deploy to production, which makes them one of the most valuable escalation targets in your organization.
  • Most escalation paths are misconfigurations, not exploits. Broad default tokens, pull_request_target workflows that run fork code, and long-lived cloud keys do more damage than any zero-day.
  • Container privilege escalation turns one job into the whole runner. Privileged containers, root users and a mounted Docker socket make the build container a doorway, not a boundary.
  • It already happens at scale. The CHAINDROP worm used elevated access on GitHub Actions runners to read credentials straight out of runner memory.
  • The fix is least privilege, enforced continuously. Scope every token, harden every container and detect permission drift before an attacker finds it.

What it is a vulnerability?

A privilege escalation vulnerability is any weakness that lets a user, process, or piece of code gain permissions beyond what it was meant to have. MITRE ATT&CK tracks it as its own tactic, TA0004: Privilege Escalation, because it’s the step that turns a small foothold into real damage.

There are two classic forms:

  • Vertical escalation: moving up, for example from a regular user to root, or from a read-only token to one that can write.
  • Horizontal escalation: moving sideways, for example using one job’s access to reach another team’s repository, secrets, or environment.

Attackers exploit a privilege escalation vulnerability through three kinds of weakness: software bugs, misconfigurations, and excessive permissions. On servers, bugs get most of the attention. In CI/CD pipelines, misconfigurations and excessive permissions do almost all of the work.

Why it is so dangerous in CI/CD pipelines

A pipeline isn’t just a build tool. It’s an automated identity with some of the broadest access in your company. A typical job can:

  • Check out and modify source code
  • Read secrets from environment variables, vaults, and cloud metadata services
  • Publish packages, images and release artifacts
  • Deploy to staging and production

The OWASP Top 10 CI/CD Security Risks names this problem directly. Its risk CICD-SEC-5: Insufficient Pipeline-Based Access Controls describes how attackers who run malicious code in a pipeline abuse the permissions granted to it to move laterally, inside or outside the CI/CD system.

This isn’t theoretical. During the CHAINDROP campaign in August 2026, the malware extracted temporary credentials from GitHub Actions runner memory and used stolen publishing tokens to infect more packages. On Linux runners, the payload ran its collector through sudo to read the runner process’s memory. That is privilege escalation in CI/CD pipelines in its purest form: a poisoned dependency, elevated access on the runner, and every secret the job could touch. It’s the same pattern we see in our weekly findings on malicious npm packages.

Where does a privilege escalation vulnerability hide in a pipeline?

Six common paths, what each one unlocks for an attacker, and the control that closes it.

Escalation pathHow it happensWhat the attacker getsHow to close it
Overprivileged pipeline tokenWorkflows run with broad default token scopes because no permissions block is setWrite access to code, releases and other workflowsSet read-only defaults and grant write access per job, only where needed
Poisoned pipeline executionpull_request_target or similar triggers check out and run code from an untrusted forkRepository secrets and a write token, from a single pull requestNever run fork code in a privileged context; split trusted and untrusted jobs
Container privilege escalationBuild containers run as root, in privileged mode, or with the Docker socket mountedRoot on the runner host and access to every job it runsRun as non-root, drop capabilities and block privilege escalation in the container spec
Long-lived cloud credentialsStatic cloud keys stored as secrets or environment variablesPersistent access to cloud accounts, long after the job endsUse short-lived, federated credentials and revoke exposed secrets automatically
Persistent self-hosted runnersRunners are reused across jobs and repositories without being rebuiltPersistence, and the ability to tamper with other teams' buildsUse ephemeral runners and isolate them per trust level
Overprivileged human accountsInactive admins, outside collaborators and unreviewed permission changes pile upA valid account that can change pipelines and branch protectionsReview access continuously and alert on anomalous permission changes

Container privilege escalation: when the build container isn’t a boundary

Containers feel like isolation, so teams often treat them as a security boundary. In CI/CD, they frequently aren’t one. Container privilege escalation happens when code inside a build container gains control of the host, and with it every other job that runs there.

Three settings account for most cases:

  1. Running as root. If the process inside the container is root, any breakout starts from the strongest possible position.
  2. Privileged mode. A privileged container has almost the same access to the host as a process running directly on it.
  3. A mounted Docker socket. Mounting /var/run/docker.sock into a job so it can build images effectively hands that job root on the host, because it can start new privileged containers.

Security researchers have shown how this plays out in real CI systems. In one well-documented case, researchers went from build scripts running inside a CI container to a full container escape on Cloudflare Pages’ build hosts, precisely because the container was being treated as the security boundary.

Here’s what a hardened Kubernetes job spec looks like. The key setting is allowPrivilegeEscalation: false, which prevents a process from gaining more privileges than its parent, for example through setuid binaries.

ci-build-pod.yamlKubernetes
# Hardened build pod: blocks the most common container privilege escalation paths
apiVersion: v1
kind: Pod
metadata:
  name: ci-build
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: build
      image: registry.example.com/build-image@sha256:<digest>
      securityContext:
        allowPrivilegeEscalation: false
        privileged: false
        readOnlyRootFilesystem: true
        capabilities:				

The same principle applies to the Dockerfile itself. Add a non-root user and switch to it before the entrypoint:

DockerfileDocker
# Run the container as a non-root user
FROM node:22-slim
RUN useradd --uid 10001 --create-home builder
WORKDIR /app
COPY --chown=builder:builder . .
USER builder
CMD ["node", "index.js"]
Why it matters: without a USER instruction, the container runs as root. Switching to a dedicated user before the entrypoint means a compromised process starts with the least privilege possible.

The Kubernetes documentation on configuring a security context covers each of these settings in detail.

GitHub Actions: an escalation vulnerability hiding in plain sight

GitHub Actions is where many teams first encounter privilege escalation in CI/CD pipelines, because the dangerous patterns look completely ordinary. Two are worth checking in every repository today.

Token scope. Every workflow gets a GITHUB_TOKEN. GitHub’s own guidance on automatic token authentication is clear: an action can reach that token even if you don’t pass it explicitly, so you should always limit its permissions to the minimum. Setting read-only permissions at the top of the workflow and granting write access per job removes the most common escalation path in one step:

.github/workflows/build.ymlGitHub Actions
name: build
on: [push]

# Default for every job: read only
permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # Pin third-party actions to a full commit SHA, not a mutable tag
      - uses: actions/checkout@<full-commit-sha>
      - run: npm ci && npm test

  release:
    needs: test
    runs-on: ubuntu-latest
    # Only this job can write, and only what it needs
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@<full-commit-sha>
      - run: ./scripts/release.sh
Why it matters: every job starts read-only, and only the release job can write. If a dependency in the test job is compromised, the token it can reach has no write access to your repository.

Untrusted triggers. Workflows triggered by pull_request_target run with the target repository’s secrets and a write-capable token, even when the pull request comes from a fork. If that workflow then checks out and runs the fork’s code, anyone can open a pull request and execute code with your privileges. That’s a privilege escalation vulnerability that needs no exploit at all, just a pull request. Keep privileged steps on trusted code, and run untrusted code in a separate workflow without secrets.

If you want to see these patterns in a safe place, the xygeni-goat repository collects deliberately insecure pipeline and IaC configurations for training. For a broader review of your GitHub setup, see our guide on how to know if a GitHub app or repository is safe.

How to prevent a privilege escalation vulnerability in CI/CD pipelines

Closing privilege escalation in CI/CD pipelines comes down to one principle: least privilege, applied at every layer and checked continuously rather than once. A practical checklist:

  1. Scope every token. Read-only by default, write access per job, and no organization-wide tokens in repository workflows.
  2. Separate trusted and untrusted code. Never run code from forks or external contributors in a job that holds secrets.
  3. Harden every build container. Non-root users, no privileged mode, no Docker socket, capabilities dropped, allowPrivilegeEscalation: false.
  4. Replace long-lived secrets. Prefer short-lived federated credentials, and revoke anything exposed immediately.
  5. Pin what you run. Reference third-party actions and images by commit SHA or digest, so a compromised tag can’t change your pipeline.
  6. Watch for drift. Permissions widen over time. Alert on new admins, weakened branch protections and unexpected workflow changes.
  7. Gate the pipeline. Fail the build when a critical misconfiguration appears, before it merges.

The hard part isn’t knowing these rules. It’s enforcing them across hundreds of repositories and workflows that change every day.

How does Xygeni stop a privilege escalation vulnerability in CI/CD?

Each escalation path, matched to the Xygeni capability that detects or blocks it.

RiskWhat Xygeni does
Pipeline misconfigurationsMisconfiguration detectors scan CI job definitions, build scripts and configuration files across GitHub, GitLab, Azure DevOps, Bitbucket, CircleCI and Jenkins, and flag permissions wider than best practice allows
Container privilege escalationIaC and container checks cover Dockerfiles, docker-compose files, Kubernetes manifests and Helm charts, including containers running as root
Overprivileged and inactive usersLeast-privilege analysis identifies inactive and overprivileged users, and the Health Check turns each finding into a ticket
Permission driftAnomaly detection alerts on unusual permission changes, anomalous merges and unexpected plugin installations
Exposed credentialsSecrets detection covers code, pipelines and container images, with automatic revocation for supported secret types
Malicious code in the pipelineBlocks reverse shells and malware downloads in pipelines in real time, and MEW detects malicious packages before a signature exists
EnforcementPre-commit hooks and CI guardrails fail the build on critical issues, with custom YAML policies for your own rules

Checks align with the OWASP Top 10 CI/CD Security Risks and standards such as CIS, NIST, and OpenSSF. Every finding flows into Xygeni ASPM, where it’s prioritized alongside code, dependency, and secrets findings, so the privilege escalation vulnerability that actually reaches production gets fixed first.

Most privilege escalation in CI/CD pipelines is already sitting in your workflow files, waiting for untrusted code to run. 

FAQ

What is a privilege escalation vulnerability in CI/CD?

It’s any weakness that lets code running in a pipeline gain more access than the job requires, such as an overprivileged token, a workflow that runs untrusted code with secrets, or a build container that can reach the host.

What is container privilege escalation?

Container privilege escalation is when a process inside a container gains higher privileges, often root on the host. Common causes are running as root, privileged mode, and a mounted Docker socket.

Does allowPrivilegeEscalation: false stop container escapes?

It blocks one important path: a process gaining more privileges than its parent, for example through setuid binaries. It works best combined with a non-root user, dropped capabilities, and no privileged mode.

Is pull_request_target always dangerous?

Not by itself. It becomes a privilege escalation vulnerability when the workflow checks out and runs code from the pull request, because that code then runs with your secrets and a write-capable token.

How do I find privilege escalation paths across many repositories?

Manual reviews don’t scale. An automated CI/CD security tool scans every workflow, container spec, and permission set continuously, and alerts when something widens.

sca-tools-software-composition-analysis-tools
Prioritize, remediate, and secure your software risks
Get your Free Account.
No credit card required.

Secure your software development and delivery

with Xygeni Product Suite