Exploiting CI/CD with Style(lint): LOTP Guide

Sébastien Graveline

 

TL;DR: CI/CD remains a stealthy and soft target for supply chain attacks—especially via linters, formatters, build and test tools. This guide breaks down Living Off the Pipeline (LOTP) techniques, where attackers exploit CI tools already present and without modifying the workflow itself—using config files, plugins, and environment variables instead.

Introduction

One of the cornerstones of open source is the pull request mechanism that lets anyone contribute by adding features, squashing bugs, or simply refining the code. But as with any open door, vulnerabilities creep in. Over the years, so-called pwn requests have emerged, where attackers sneak in malicious payloads via pull requests. Even in 2025, with tightened default permissions and hardened workflow events, vulnerable CI/CD pipelines still exist, sometimes in surprisingly stealthy ways.

If you’re scratching your head wondering, “What exactly is a pwn request?” check out our earlier post, Under The Radar: Zero-Days in Open Source Build Pipelines, where we highlighted how a workflow with certain permissions or secrets on an upstream repo can be compromised by an attacker-controlled fork.

Executing Untrusted Code

Pwn requests are easy to dismiss as common sense:

“Run a bash script from an untrusted source, and yeah, you’ll get hacked eventually.”
- Average Hacker News commenter circa 2016

True enough, but the devil is in the details. Most attacks exploit how CI/CD tools often execute code in unexpected ways, catching even the most security-conscious people off guard.

Living Off the Pipeline (LOTP)

Enter the Living Off the Pipeline (LOTP) project. As detailed in The Tale of a Supply Chain Near-Miss Incident, LOTP catalogs common CI/CD tools that can be weaponized if an attacker controls their context. This context can include configuration and source files, environment variables, and other elements that do not require modifying the workflow itself.

So far, we’ve identified six primary methods in the LOTP playbook. Each tool's name links to a more detailed explanation:

  • Holy Grail: Rare but dangerous. Tools like yarn can, via a config file, overwrite themselves to execute arbitrary commands.
  • Custom Module: The sneakiest and most frequent. Linters and formatters such as golangci-lint and stylelint allow plugins to run in their native context. If an attacker controls the config, they can inject a custom plugin to run arbitrary code. A limited yet crafty variant is seen with vale, a linter that can exfiltrate secrets through custom styling and symbolic link.
  • Direct Code Execution: Tools like make and rake run shell commands embedded in files. Another example is go generate, which executes commands from any *.go file in the project.
  • Build: Build tools such as MSBuild and docker execute code or allow arbitrary reads during the build process.
  • Tests: Automated test tools like cargo test execute the tests, which are just code. If an attacker can modify the tests, remote code execution (RCE) becomes trivial.
  • Local GitHub Action: A surprisingly common vector: if a local github action (e.g., uses: ./.github/actions/any) is used, an attacker can simply overwrite it.

The next two RCE vectors are also found in the wild, but they only come into play when the code is run, packaged, or exported. Since executing code naturally paves the way for RCE, we’ve placed them in a separate category, even though their signs might not be as obvious as you’d expect.

  • Source Code Modification: If attacker-controlled code gets executed; think go run, ruby, or python - RCE is almost inevitable.
  • Dependencies: Tools like bundler and go mod rely on package files. If an attacker tweaks these to pull in malicious dependencies, RCE follows. Tools like npm can also be manipulated to use an attacker-controlled registry through a config file.

Protecting Against LOTP Attacks

In addition to the essential recommendations in Under The Radar: Zero-Days in Open Source Build Pipelines, try these extra tactics to further raise the bar against potential attacks:

  • For workflow_run events, use branches: '*' to ensure workflows only trigger for pull requests from the upstream repository.
  • Don’t forget that pull_request_target is vulnerable in any branch. Yes, even those in forgotten branches, left to rot for months, with vulnerabilities already patched in the default branch.
  • When cloning an untrusted repo (with actions/checkout), specify the output path to a dedicated subdirectory. Since many tools scan the current working directory for configuration files, isolating the clone can block some attacks.
  • Always specify the configuration path. By directing the tool from a controlled directory, you can prevent LOTP attacks that rely on reading arbitrary config files.
  • One particularly effective strategy for tool makers wanting custom plugin support is the technique employed by Trivy. Allowing external modules through a WASM module-designed as a Web sandbox-blocks most custom module attacks outright.

What’s Next

Over the past months, we’ve greatly expanded the LOTP inventory to include more tools vulnerable to attacker-controlled context files. But the threat landscape is always evolving. Here are a couple of additional vectors to keep on your radar:

  • Environment Variables: Tools like bash and tar can be manipulated via environment variables. If an attacker can control inputs to GITHUB_ENV, RCE is essentially guaranteed through bash, which is the default shell for GitHub Runners.
  • Standard Output (stdout) Pollution: Most tools’ ability to write to stdout can be exploited to introduce logical errors in workflows. As demonstrated at Defcon Paris 2024, attackers can use this to trigger unintended behavior via GitHub Action commands. While these exploits are trickier to detect and are often overwritten by GITHUB_OUTPUT one of the most dangerous uses is recovering masked secrets in logs. So don't print secrets in your logs! They might not really be masked...

Under The Radar: Zero-Days in Open Source Build Pipelines

Alexis-Maurer Fortin

TL;DR: Our deep dive into open source projects’ CI/CD systems has revealed that build pipelines...

Read more

From Pandora's Box to Nuclear Fishing: Escalating Threats in Build Pipelines Security

Image of François Proulx
François Proulx

TL;DR: We've been quiet lately—despite recent Supply Chain drama—because we wanted a clearer...

Read more