Skip to content
Latchkey

octoscan: Deep Static Scan of Actions Workflows

octoscan statically scans GitHub Actions workflows for command injection, dangerous checkout of untrusted refs, and other exploitable patterns.

octoscan overlaps with zizmor but leans into deep dataflow of untrusted input into shell. Running both catches more supply-chain and injection issues than either alone, at the cost of some duplicate findings.

What it does

octoscan parses workflows and traces untrusted inputs (event payload fields, issue titles, PR bodies) into run: blocks and action inputs, flagging injectable sinks. It also flags pull_request_target combined with checkout of the PR head and other known-dangerous patterns.

Common usage

Terminal
octoscan scan .github/workflows/
octoscan scan --json .github/workflows/ > octoscan.json
octoscan scan --disable-rules dangerous-checkout .github/workflows/
octoscan scan --filter-triggers push,pull_request .

Options

FlagWhat it does
scan <path>Scan a workflow file or directory
--jsonEmit machine-readable JSON output
--disable-rules <list>Disable specific rule ids
--filter-triggers <list>Only analyze workflows with these triggers
--verbosePrint detailed analysis

In CI

Run octoscan in a security PR check on any workflow change. Because it and zizmor both report unpinned-action and injection issues, gate on one and treat the other as advisory to keep signal clean, and fix unpinned findings with pinact or ratchet.

Common errors in CI

Findings read like [HIGH] dangerous-checkout: workflow checks out untrusted code with elevated permissions and [HIGH] shell-injection: ${{ github.event.issue.title }} used in run block. error: could not parse workflow means malformed YAML (lint with actionlint first). command not found: octoscan means the binary is not installed.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →