Skip to content

SHEET 01 / WORKFLOW GRAPH

Your pipeline, drawn.
The flaws, marked.

Daggler parses GitHub Actions workflows into a typed graph, validates them in five layers and scores their security. Below is an example release workflow with common mistakes, and what daggler lint actually reported on it, pinned to the job where it was found.

Open the editorGet started$ npx daggler-cli lint
on: pull_request_target · push tags v*7lintno needs1testno needs2buildneeds lint, test3e2eneeds builddocsneeds buildpublishneeds e2e, docs4589deployneeds publish6107 JOBS · 7 NEEDS EDGES · 5 STAGESon: pull_request_target · push tags7lintno needs1testno needs2buildneeds lint, test3e2eneeds builddocsneeds buildpublishneeds e2e, docs4589deployneeds publish6107 JOBS · 7 NEEDS EDGES · 5 STAGES
Findings schedule from daggler lint on examples/insecure-release.yml · security grade F, 0/100 · 6 errors, 4 warnings
No.CodeWhereFinding
1POL007lint · 14:9Action ref uses a branch (error)
2POL008test · 21:9Shell injection from untrusted input (error)
3POL002build · 29:9Third-party action not SHA-pinned (error)
4POL003publish · 54:5Privileged token on an untrusted event (error)
5POL004publish · 59:9Secret reachable from untrusted event (error)
6POL004deploy · 68:9Secret reachable from untrusted event (error)
7POL001workflow · permissionsNo top-level permissions (warning)
8POL006publish · 51:3Deploy without environment gate (warning)
9POL009publish · 51:3OIDC permission without a cloud step (warning)
10POL006deploy · 63:3Deploy without environment gate (warning)

n error   n warning   job with findings

Titleinsecure-release.yml, dependency graph
Projectdaggler
Sheet1 of 6
Rev0.1.2
Drawn bydaggler lint --no-color

SHEET 02 / REPORT

The same file, as the terminal prints it

This is the unedited output of npx daggler-cli@0.1.2 lint --no-color on the workflow above (examples/insecure-release.yml in the repo). Every line is addressed: file, line, column, and what to do about it. The exit code is 1 whenever there is an error, so it can gate CI.

$ npx daggler-cli lint --no-color examples/insecure-release.yml
────────────────────────────────────────────────────────────────────────  examples/insecure-release.yml  Security F 0/100  6 errors  ·  4 warnings  ·  0 info  ⚑ Unpinned third-party actions  ⚑ Untrusted input reaches privileged context  ⚑ Shell injection risk   ● POL007  examples/insecure-release.yml:14:9  Action ref uses a branch  └─ 'actions/checkout@main' tracks a moving branch — each run may execute different code. Pin to a release tag or a full commit SHA.  ● POL008  examples/insecure-release.yml:21:9  Shell injection from untrusted input  └─ Untrusted 'github.event.pull_request.title' is interpolated into a shell script — an attacker can inject commands. Pass it via an env var and quote it instead.  ● POL002  examples/insecure-release.yml:29:9  Third-party action not SHA-pinned  └─ 'docker/build-push-action@v5' is pinned to a mutable tag — an upstream push can silently change what runs. Pin to a full commit SHA instead.  ● POL003  examples/insecure-release.yml:54:5  Privileged token on an untrusted event  └─ Job 'publish' runs on pull_request_target (an untrusted event) and grants contents permission — attacker-controlled code can exfiltrate secrets or modify the repository.  ● POL004  examples/insecure-release.yml:59:9  Secret reachable from untrusted event  └─ Secret 'NPM_TOKEN' is exposed to a workflow that runs on an untrusted event and may execute attacker-controlled code.  ● POL004  examples/insecure-release.yml:68:9  Secret reachable from untrusted event  └─ Secret 'DEPLOY_KEY' is exposed to a workflow that runs on an untrusted event and may execute attacker-controlled code.  ▲ POL001  examples/insecure-release.yml:workflow:permissions  No top-level permissions  └─ No top-level 'permissions:' block — the workflow inherits broad default token scopes; add an explicit least-privilege block.  ▲ POL006  examples/insecure-release.yml:51:3  Deploy without environment gate  └─ Deploy-like job 'publish' has no `environment:` protection gate — add one to require reviewer approval before deploying.  ▲ POL009  examples/insecure-release.yml:51:3  OIDC permission without a cloud step  └─ Job 'publish' grants id-token:write but none of its steps use a recognized cloud-auth (OIDC) action — remove the permission or add the appropriate cloud-auth action.  ▲ POL006  examples/insecure-release.yml:63:3  Deploy without environment gate  └─ Deploy-like job 'deploy' has no `environment:` protection gate — add one to require reviewer approval before deploying. ════════════════════════════════════════════════════════════════════════  Summary  6 errors  ·  4 warnings  ·  0 info  in 1 file  ·  worst security grade F════════════════════════════════════════════════════════════════════════
TitleLint report, verbatim
Projectdaggler
Sheet2 of 6
Rev0.1.2
Sourcenpx daggler-cli@0.1.2

SHEET 03 / SECTION A-A

Five layers, cut through the pipeline

Workflow YAML becomes a typed IR with a source map, then a job graph. Each layer runs over the same parse and adds diagnostics; the policy engine sits on top and scores the result from A to F. The whole pipeline is TypeScript and runs in the browser.

  1. L0ParsersyntaxYAML syntax errors and warnings, with line and column.
  2. L1SchemaSCHEMA001-005Required fields, empty step lists, missing runs-on, no jobs, no triggers.
  3. L2ExpressionsEXPR001-004Context availability inside ${{ }}: matrix, needs, steps, inputs.
  4. L3GraphSEM001-003, 005needs cycles, dangling references, unreachable jobs, oversized matrices.
  5. L4ActionsACT001-005uses: steps checked against a curated catalog: inputs, outputs, deprecated majors.
TitleValidation layers
Projectdaggler
Sheet3 of 6
Rev0.1.2

SHEET 04 / SCHEDULE OF RULES

Thirteen policy rules

POL001 to POL010 cover permissions, pinning, untrusted triggers and injection. AGENT001 to AGENT003 cover AI-agent workflows: prompt injection, over-permitted agents and executed model output. Rules are grouped into six packs.

CodeSeverityRulePacks
POL001warningNo top-level permissions blockoss-maintainer, enterprise-least-privilege
POL002errorThird-party action not SHA-pinnedoss-maintainer, release-hardening, enterprise-least-privilege
POL003errorPrivileged token on an untrusted eventoss-maintainer, enterprise-least-privilege
POL004errorSecret reachable from untrusted eventoss-maintainer
POL005warningBroad contents:write on PR workflowoss-maintainer
POL006warningDeploy without environment gaterelease-hardening, cloud-deploy
POL007errorAction ref uses a branchrelease-hardening, enterprise-least-privilege
POL008errorShell injection from untrusted inputoss-maintainer, enterprise-least-privilege
POL009warningOIDC permission without a cloud stepcloud-deploy, enterprise-least-privilege
POL010warningWorkflow modifies workflow filesenterprise-least-privilege
AGENT001errorUntrusted input flows into an AI agentai-agent-safety
AGENT002warningOver-permitted AI agentai-agent-safety
AGENT003errorAgent output executedai-agent-safety
TitlePolicy rules
Projectdaggler
Sheet4 of 6
Rev0.1.2

SHEET 05 / DETAIL VIEWS

The editor

Captures of the real editor from a checkout, using the real engine and bundled sample workflows. The hosted editor runs the same engine in your browser: graph, diagnostics, event simulation and policy checks. Running workflows needs the CLI or a local build.

The Daggler editor: job graph, Monaco YAML with diagnostics, inspector, confidence ladder
Detail A Live job graph, Monaco YAML with source-mapped diagnostics, a typed inspector and one-click quick-fixes.
Security view of an AI-agent workflow graded F with AGENT001 findings
Detail B Security view: an AI-agent workflow graded F, with AGENT001 and POL003 findings.
The Local rung of the confidence ladder streaming an act plan into the Run panel
Detail C The Local rung runs act against Docker and streams the plan into the Run panel.
TitleEditor, local build
Projectdaggler
Sheet5 of 6
Rev0.1.2

SHEET 06 / GENERAL NOTES

Install and run

  1. Run the CLI once, Node 20 or newer. With no arguments lint scans .github/workflows/.

    npx daggler-cli lint
  2. Or install it. The package is daggler-cli; the binary is daggler.

    npm install -g daggler-cli
    daggler lint
  3. Open the hosted editor, no install: alliecatowo.github.io/daggler/app/editor. Or build the full editor from source (Node 20+, pnpm 10+).

    git clone https://github.com/alliecatowo/daggler
    cd daggler && pnpm install
    pnpm --filter @daggler/web dev   # http://localhost:3737
TitleInstall
Projectdaggler
Sheet6 of 6
Rev0.1.2