Skip to main content

Scan a local repo

pipefort -p /path/to/your/repo
The scanner looks for .github/workflows/*.yml and *.yaml inside the given path. If that directory doesn’t exist, it falls back to walking the whole tree for any YAML file that looks like a workflow. If you omit -p, the current working directory (.) is used.

Scan a single workflow file

pipefort -f .github/workflows/deploy.yml
-f overrides -p. Useful for editor integrations or focused triage.

Scan a remote GitHub repo

pipefort -g owner/repo
pipefort -g https://github.com/owner/repo.git
The CLI runs git clone --depth 1 into a temp directory, scans it, and cleans up. Add --keep-temp to leave the clone on disk for inspection.

Scan an entire organization

pipefort --org my-org
pipefort --org my-org -o sarif > org.sarif
--org enumerates every repository owned by a GitHub organization or user and scans each one by fetching its workflow YAML over the API — no cloning, with bounded concurrency. It requires a token (--github-token, $GITHUB_TOKEN, $GH_TOKEN, or gh auth login); private repos need one with repo scope. Each repository’s own .pipefort.yml is fetched and applied to that repo’s findings, and the online supply-chain audits run automatically (the token is present). Console output leads with a per-repo severity summary, then the full findings grouped by owner/repo/path. --fail-on is evaluated against the aggregate across all repos.

JSON output

pipefort -p . -o json
Emits a JSON object on stdout with two keys: findings (the flat list of Finding objects) and toxic_combinations (the Attacker Mind correlations). Both keys are always present.
{
  "findings": [
    {
      "file": ".github/workflows/release.yml",
      "line": 12,
      "column": 5,
      "severity": "HIGH",
      "category": "CICD-SEC-4",
      "rule_id": "cicd-sec-4-ppe-shell-injection",
      "title": "Poisoned Pipeline Execution (Shell Injection)",
      "description": "...",
      "recommendation": "..."
    }
  ],
  "toxic_combinations": [
    {
      "id": "pwn-request",
      "title": "Pwn Request — untrusted PR code runs with a writable token",
      "severity": "CRITICAL",
      "scope": "file",
      "file": ".github/workflows/release.yml",
      "impact": "...",
      "break_chain": "...",
      "break_chain_rule": "cicd-sec-1-ppe-checkout",
      "stages": [{ "order": 0, "title": "...", "description": "...", "rule_id": "..." }],
      "components": [{ "rule_id": "cicd-sec-1-ppe-checkout", "finding": { "...": "..." } }]
    }
  ]
}
Breaking change. Earlier releases emitted a bare JSON array of findings. The output is now an object — read findings from the findings key (e.g. pipefort -p . -o json | jq '.findings').
Pipe to jq for filtering, or feed it into another tool. The console output (the default) is human-readable but the JSON form is the stable contract for automation.

Filter to OWASP-only

pipefort -p . -r owasp
--ruleset owasp (-r owasp) keeps only findings with category prefix CICD-SEC-. The default all includes the three best-practice checks too. See Rules reference.

Apply automatic fixes

pipefort -p . --fix
Rewrites workflow YAML in place for the fixable categories, then re-scans to show what’s left. See Auto-fix for the exact rewrite rules.
--fix is not supported with -g owner/repo. Clone the repo yourself if you want to fix and review the diff.