DEV Community

Nathan Sportsman
Nathan Sportsman

Posted on

We Kept Breaking CI/CD Pipelines Across Every Platform. So We Built One Tool to Secure All of Them.

Your perimeter is hardened. Your EDR is mature. MFA is everywhere.

And then there's the GitHub Actions workflow that runs code from any fork that opens a pull request.

CI/CD pipelines have become the access vector of choice for attackers — and for Praetorian's red team. We released Gato in 2023 to help others prevent the GitHub Actions vulnerabilities we kept exploiting. Then Glato for GitLab CI.

Useful tools. But every enterprise we assessed wasn't running one platform — it was three or four. GitHub for open-source. Azure DevOps for internal deployments. A GitLab instance the platform team owns. Jenkins on a server from 2017 that nobody wants to touch.

Assessing those environments meant different tools for each platform, manual reviews where tooling didn't exist, and losing the consistency that makes security work repeatable.

So we rebuilt from scratch.


Introducing Trajan

Trajan is an open-source, cross-platform CI/CD vulnerability detection and attack automation tool. It currently supports:

  • GitHub Actions
  • GitLab CI
  • Azure DevOps
  • Jenkins

With Bitbucket Pipelines, CircleCI, AWS CodePipeline, and Google Cloud Build in active development.

32 detection plugins. 24 attack plugins. One binary.

The core engine works the same way across all platforms: enumerate access → fetch workflow files via API → parse into a dependency graph → run detection plugins → optionally validate with attack modules.


What Trajan Finds

🔴 Poisoned Pipeline Execution

The most common critical finding in CI/CD assessments. The mechanics vary by platform — expression injection in GitHub Actions, variable interpolation in Azure DevOps, YAML anchors in GitLab — but the result is always the same: attacker-controlled code running inside your build environment with access to your secrets.

Trajan builds a workflow graph, traces user-controllable input to execution sinks, and identifies the exact path. Not just "this looks suspicious" — the precise nodes where a PR title becomes a shell command.

🔴 Secrets Exposure

Secrets leak two ways:

  1. Script behavior — echoing variables, dumping credentials to logs, tokens in URL parameters
  2. Structural misconfigurations — service connections scoped too broadly, secrets accessible on untrusted triggers, variable groups shared across projects

The second category is the dangerous one. It doesn't show up in any individual workflow file. Trajan maps cross-workflow resource relationships to surface overpermissioned secrets and hijackable service connections.

An upcoming integration with Titus, our secrets scanner, will extend this to credential detection in build logs and artifacts.

🔴 Self-Hosted Runners

Non-ephemeral runners are a lateral movement gift. They:

  • Persist between jobs
  • Accumulate filesystem state
  • Maintain network access to internal systems
  • Often retain service account credentials from previous runs

If a vulnerable workflow runs on self-hosted infrastructure, the blast radius expands fast. Trajan identifies these jobs across all supported platforms and provides command execution capabilities for testing persistence.

🤖 AI/LLM Pipeline Vulnerabilities

This is the category everyone is about to care about.

GitHub Copilot is reviewing PRs. CodeRabbit is suggesting changes. Custom model workflows are analyzing commits. These AI actions sit inside privileged build environments, have access to repository secrets, and are often configured to receive untrusted input from pull requests.

The attack pattern is straightforward: craft a malicious PR comment → AI action processes it → credentials exfiltrated in the model's output.

Trajan detects these conditions through dedicated plugins covering:

  • Token exfiltration
  • Code injection
  • Workflow sabotage
  • MCP abuse

It integrates Julius (our LLM service fingerprinting tool) to identify deployed AI services from workflow YAML files, then hands off to Augustus (our LLM vulnerability scanner) to validate exploitability across 210+ adversarial prompt injection payloads in six attack categories.

Organizations embedding AI into build pipelines need to treat these workflows as privileged code execution surfaces — not helpful automation.


Three Modules

enumerate — Map Your Attack Surface First

Validate credentials, discover repositories, identify secrets, find runners and build agents, enumerate service connections. Before you scan or attack anything, answer two questions: what can this token reach, and where are the high-value targets?

> trajan ado enumerate variable-groups --org Middle-Earth-Arda --project Lothlorien

ID  NAME                    TYPE  VARIABLES
6   lothlorien-db-creds     Vsts  6
5   lothlorien-cloud-creds  Vsts  5
4   lothlorien-app-config   Vsts  6
Total: 3 variable groups
Enter fullscreen mode Exit fullscreen mode

scan — Run Detection Plugins Against Pipeline Configs

Trajan fetches workflow files, parses them into a graph, and runs registered detectors. Same vulnerability classes across every platform — Trajan handles the syntax differences.

> trajan ado scan --org Middle-Earth-Arda --repo Lothlorien/Galadriel_repo --detailed --capabilities secrets-exposure

[HIGH] unredacted_secrets
Workflow: unredacted_secrets.yml
Location: Line 20, Step: Debug Cloud Credentials

18   steps:
19     - script: |
20 →       echo "Debug: AWS_SECRET_ACCESS_KEY=$(AWS_SECRET_ACCESS_KEY)"
21         echo "Debug: AZURE_CLIENT_SECRET=$(AZURE_CLIENT_SECRET)"
22       displayName: 'Debug Cloud Credentials'
Enter fullscreen mode Exit fullscreen mode

attack — Validate Exploitability

Every attack plugin requires explicit opt-in, tracks all created artifacts in a session file, and supports cleanup after the engagement. The output is evidence, not just detection.

> trajan ado attack --org Middle-Earth-Arda --repo Lothlorien/Galadriel_repo --plugin secrets-dump --confirm

[SUCCESS] ado-secrets-dump
146 environment variables, 3 variable groups (15 secrets)
Secrets written to: ado-secrets-07b00b13.txt

To cleanup: trajan ado attack cleanup --session 07b00b13
Enter fullscreen mode Exit fullscreen mode

Bonus: It Runs in the Browser

Trajan compiles to WebAssembly and ships as a single HTML file — same detection engine, same attack plugins, no installation required. For assessments where dropping a binary onto a system is friction, the web version removes the barrier entirely.


Getting Started

# Grab the latest release for your platform
# Linux, macOS, and Windows binaries available

# Enumerate your ADO environment
trajan ado enumerate token --org <your-org>

# Scan a repository
trajan github scan --repo <owner/repo>

# Full docs and examples at:
# https://github.com/praetorian-inc/trajan
Enter fullscreen mode Exit fullscreen mode

👉 github.com/praetorian-inc/trajan

If you find bugs, want to contribute detection or attack plugins, or have feature requests — open an issue. Trajan is under active development and we want to hear how it holds up in real environments.


Trajan is part of Praetorian's 12 Caesars open-source security tool series. The series also includes Julius (LLM fingerprinting), Augustus (LLM vulnerability scanning), Brutus (credential testing), Titus (secrets scanning), and Nerva (service fingerprinting).

Top comments (0)