<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Grackle: Fork-Triggerable AI Agent Scanner for CI :: Grackle</title><link>https://cpeoples.github.io/grackle/index.html</link><description>Standalone scanner that detects fork-triggerable AI coding agents with repository write access in GitHub Actions and GitLab CI. 36 rules across 35 agent families, with SARIF, GitLab SAST, and CycloneDX output and dynamic remediations.</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 23 Jul 2026 14:30:44 +0000</lastBuildDate><atom:link href="https://cpeoples.github.io/grackle/index.xml" rel="self" type="application/rss+xml"/><item><title>Detection Rules</title><link>https://cpeoples.github.io/grackle/rules/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/rules/index.html</guid><description>grackle ships 36 rules covering fork-triggerable AI coding agents that can write to the repository: 32 critical, 4 high. Each rule fires only when a workflow is fork-reachable, has no author gate, and runs the agent in a job that can mutate the repository.
Rules are grouped by how they are post-filtered, not by vendor:
Installed agents anchor on an agent CLI or action name and confirm the family with a whole-file proof. Action-configured agents anchor on an action opened to forks (write sandbox, allowed_non_write_users: "*", and similar). Shell-exec secret exposure flags an agent handed an arbitrary shell in a fork-reachable job that carries a secret it could exfiltrate. GitLab CI rules use GitLab-native reachability rather than the GitHub on:/permissions: model.</description></item><item><title>CLI Reference</title><link>https://cpeoples.github.io/grackle/cli/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/cli/index.html</guid><description>1 2 3 4 5 6 7 8 9 10 11 grackle [PATH] # scan a file or directory (default: .) grackle -f json PATH # choose an output format grackle -o report.sarif PATH # write to a file (format inferred from extension) grackle --json PATH # shorthand for -f json grackle --debug PATH # print per-file scan diagnostics to stderr grackle --list-rules # print the rule inventory grackle --rules-json # print the full rule catalog with metadata as JSON grackle --self-test # validate every rule against its built-in examples grackle --github-comment PATH # post PR comments (inside a GitHub Actions PR) grackle --gitlab-comment PATH # post MR comments (inside a GitLab CI pipeline) grackle --version # print the version Arguments Argument Description PATH File or directory to scan. Defaults to the current directory. A directory scan also resolves local composite actions off disk. Options Option Description -f, --format &lt;FORMAT> Output format: text, json, markdown, sarif, gitlab-sast, junit, csv, xml, yaml, html, cyclonedx. -o, --output &lt;FILE> Write the report to a file. The format is inferred from the extension unless --format is set. --json Shorthand for --format json. --debug Print per-file scan diagnostics (candidates, findings, totals) to stderr. --list-rules Print every built-in rule (id, severity, title) and exit. --rules-json Print the full rule catalog with compliance metadata as JSON and exit. This is the source the documentation site is generated from. --self-test Validate every built-in rule against its own positive and negative examples and exit. --github-comment Post a sticky summary comment and inline comments on the current GitHub pull request. See CI/CD integration. --gitlab-comment Post a sticky summary comment and inline comments on the current GitLab merge request. See CI/CD integration. --version Print the version. Exit codes Code Meaning 0 Scan completed, no findings. 1 Scan completed, at least one finding reported. 2 Usage or I/O error (bad path, unwritable output, invalid format). Format inference When --output is given without --format, the format is inferred from the file extension (.sarif, .json, .md, .html, .xml, .yaml/.yml, .csv). An explicit --format always wins.</description></item><item><title>Output Formats</title><link>https://cpeoples.github.io/grackle/output-formats/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/output-formats/index.html</guid><description>-f/--format selects the format; -o/--output writes to a file and infers the format from its extension. --json is shorthand for -f json.
Format Value Notes Text text (default) Human-readable, with the full remediation. JSON json Findings with metadata, snippet, and remediation. Markdown markdown / md One section per finding. SARIF 2.1.0 sarif Rule catalog + fixes[]; GitHub code scanning. GitLab SAST gitlab-sast gl-sast-report.json for artifacts:reports:sast. JUnit junit One failing test case per finding. CSV csv Flat table (RFC 4180). XML xml Generic findings document. YAML yaml / yml Findings with block-scalar snippet/remediation. HTML html Self-contained styled report. CycloneDX 1.5 cyclonedx SBOM vulnerabilities[]; Dependency-Track, Snyk. Every finding carries its control-framework references (CWE, OWASP AppSec, OWASP LLM, OWASP ASVS, MITRE ATT&amp;CK, MITRE ATLAS, CIS Controls, NIST 800-53, PCI-DSS, SOC 2), the offending workflow block, and a dynamic secure-fix write-up derived from that block: the vulnerable code, why it is dangerous, and a corrected workflow.</description></item><item><title>Detection Model</title><link>https://cpeoples.github.io/grackle/detection-model/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/detection-model/index.html</guid><description>Grackle does not match on a blocklist of repositories or agent names alone. It reasons structurally about three properties of a workflow, per job, and only reports when all three hold at once.
1. Fork-reachable trigger The workflow runs on an event an outside contributor can cause: pull_request_target, pull_request, issue_comment, issues, pull_request_review, pull_request_review_comment, a reusable workflow_call reached from one of these, or a workflow_run consumer chained off a fork-PR-triggered producer that ingests the fork run’s data (artifact, head_sha, or linked PR) without a same-repo guard.</description></item><item><title>Remediations</title><link>https://cpeoples.github.io/grackle/remediations/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/remediations/index.html</guid><description>Every finding grackle reports carries a remediation. A finding is not just “this is wrong” - it is “here is the vulnerable block, here is why it is exploitable, and here is a safe rewrite you can adapt.” The remediation is derived from the matched rule and the offending snippet, so it names the specific action and pin in front of you rather than a generic template.
The three parts Each finding renders as three blocks, cued by an icon:</description></item><item><title>CI/CD Integration</title><link>https://cpeoples.github.io/grackle/ci-cd/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/ci-cd/index.html</guid><description>Grackle is a single static binary with no runtime dependencies, so it drops into any pipeline. It scans a checked-out repository and exits 1 when it finds a fork-triggerable agent, which fails the job.
GitHub Actions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 name: grackle on: push: branches: [main] pull_request: permissions: contents: read security-events: write # only needed to upload SARIF jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install grackle run: cargo install --git https://github.com/cpeoples/grackle.git - name: Scan workflows run: grackle -o grackle.sarif . - name: Upload SARIF if: always() uses: github/codeql-action/upload-sarif@v3 with: sarif_file: grackle.sarif GitLab CI 1 2 3 4 5 6 7 8 9 grackle: stage: test image: rust:latest script: - cargo install --git https://github.com/cpeoples/grackle.git - grackle -f gitlab-sast -o gl-sast-report.json . artifacts: reports: sast: gl-sast-report.json The GitLab SAST report auto-populates the Security Dashboard.</description></item><item><title>Limitations</title><link>https://cpeoples.github.io/grackle/limitations/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/limitations/index.html</guid><description>Grackle is a static, structural scanner. It reads CI YAML and reasons about reachability, gating, and write capability from the file alone. That is a deliberate design choice for speed and zero false-positive noise, but it means some things are out of scope by construction.
What it reasons from Only the workflow file (and, for directory scans, one level of local composite actions). It does not evaluate expressions at runtime, resolve remote reusable workflows, or inspect repository settings.</description></item><item><title>White Paper</title><link>https://cpeoples.github.io/grackle/whitepaper/index.html</link><pubDate>Thu, 23 Jul 2026 14:30:44 +0000</pubDate><guid>https://cpeoples.github.io/grackle/whitepaper/index.html</guid><description>Abstract AI coding agents (Claude Code, Cursor, OpenCode, Codex, Gemini, and roughly two dozen others) are increasingly wired directly into CI pipelines to triage issues, review pull requests, and land fixes. When such an agent runs on untrusted input from a fork, in a job that can write to the repository, and without a check on who triggered it, prompt injection becomes remote code execution and repository takeover under the CI token.</description></item></channel></rss>