Skip to main content

harnessguard

Static hardening linter for GitHub Actions workflows that run AI agents.

Agents in CI (Claude Code Action, Gemini CLI Action, Codex, Copilot agents and friends) read attacker-controlled text — issue bodies, PR titles, comments — while the runner holds secrets and write tokens. That combination is the new CI/CD supply-chain attack surface: a public comment becomes instructions the agent obeys.

harnessguard enforces Microsoft's Agents Rule of Two: an AI-powered workflow must never combine untrusted input, privileged access, and external communication. It runs as a static, deterministic check in pull requests — it never executes your workflows or your agents.

Why

Real incidents, all from 2026:

  • Comment and Control (April 2026) — hijacked Claude Code Security Review, Gemini CLI Action and Copilot Agent via PR titles / issue bodies; leaked ANTHROPIC_API_KEY, GEMINI_API_KEY and GITHUB_TOKEN through public comments.
  • Black Hat USA 2026 (August) — an unprivileged GitHub issue reached CI runner secrets in the vendors' own repositories; Gemini CLI Action got CVE-2026-12537 (CVSS 10.0).
  • MSRC — Claude Code Action's Read tool reached /proc/self/environ; fixed in 2.1.128.

Existing Actions linters (zizmor, actionlint, poutine…) are excellent but agent-blind: they don't model "this step is an LLM that will obey text."

Research

We sampled 337 public agent workflow files (255 repos) via the GitHub code search API: 44.2% combine untrusted events with runner secrets or write permissions, and 61% of those carry no actor-association guard in the workflow file. Aggregates only — no repo is named.

Pass 2 re-scanned the full workflow set of the same 255 repos for cross-workflow artifact chains (HG007): 5.5% carry the chain, and every chain detected runs no agent on either side — a blind spot for agent-only scanners and per-file linters alike.

Pass 2.5 looked for the mirror pattern (HG008): untrusted-triggered workflows that pass secrets into an agent-bearing reusable workflow. 20 repos carry the chain; 17 of 20 come from the Gemini CLI Action dispatch template. MCP hygiene (HG010): 5 unpinned MCP server configurations, none pinned.

Pass 3 re-fetched the pass-1 corpus with the same engine three days later: 97% of files are byte-identical — zero findings fixed, zero introduced. → State of AI-agent workflows in the wild · reproduce with uv run python scripts/ecosystem_scan.py, scripts/chain_scan.py and scripts/remediation_scan.py

Install

pip install harnessguard
# or from source
uv sync && uv run harnessguard --version

Usage

# scan the current repo (finds .github/workflows/)
harnessguard scan .

# fail CI on high and above, write SARIF for code scanning
harnessguard scan . --fail-on high --sarif harnessguard.sarif

# machine-readable output
harnessguard scan . --format json

# adopt on an existing repo: record current findings, then only fail on new ones
harnessguard scan . --format json > baseline.json
harnessguard scan . --baseline baseline.json --fail-on high

# let coding agents lint the workflows they generate (stdio MCP server)
harnessguard mcp

# list rules
harnessguard rules list

Exit code is 1 when findings at or above --fail-on exist. --fail-on none reports without failing.

MCP server

harnessguard mcp serves the scanner over stdio MCP (read-only, no network): scan_repository, scan_workflow (lint YAML before writing it) and list_rules. Wire it into any MCP client:

{ "mcpServers": { "harnessguard": { "command": "uvx", "args": ["harnessguard", "mcp"] } } }

GitHub Action

name: harnessguard
on: [push, pull_request]

jobs:
  harnessguard:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: dtduc-git/harnessguard@v0.4.0
        with:
          fail-on: high

Rules

Rule Severity What it catches
HG001 critical Agent step on untrusted events with secrets in scope (job or workflow env)
HG002 high Attacker-controlled event data interpolated into an agent step
HG003 high Agent step on untrusted events with write permissions
HG004 high Agent step in a pull_request_target workflow
HG005 medium Agent step with shell/network tool grants or egress commands
HG006 high Agent job checks out an attacker-controlled ref
HG007 high Privileged workflow_run job consumes artifacts from untrusted-triggered workflows (Cordyceps chain)
HG008 high Untrusted-triggered workflow passes secrets into an agent-bearing reusable workflow
HG009 high Agent step consumes artifacts from an untrusted-triggered workflow
HG010 medium Agent step launches unpinned MCP servers or plaintext MCP endpoints

Findings map to the OWASP Top 10 for Agentic Applications (ASI01–ASI05). Jobs whose if: restricts triggering via github.actor / author_association guards get HG001/HG003 downgraded one level — reduced exposure is still flagged, just at lower severity. Rules are data — YAML in src/harnessguard/rules_data/ — and checks are small named functions in checks.py. Add your own with --rules-dir.

Design principles

  • Never executes anything. No workflow runs, no agent calls, no network.
  • Local-first. No account, no telemetry, no SaaS.
  • Deterministic. Same input → same findings; no LLM in the detection path.
  • Rules as data. Extend coverage without touching the engine.

Non-goals

  • Not a general-purpose Actions linter — use zizmor alongside it.
  • No runtime enforcement or proxy — that is a different (complementary) tool.
  • Not GitLab/Jenkins (yet).

References

  • Microsoft Security Blog — Securing CI/CD in an agentic world (Agents Rule of Two), June 2026
  • CSA — Comment and Control: GitHub AI Agents as Credential Exfiltrators, April 2026
  • OWASP — Top 10 for Agentic Applications 2026

License

Apache-2.0

Release files for harnessguard 0.6.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for harnessguard 0.6.4
File Size Uploaded
harnessguard-0.6.4.tar.gz 2.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for harnessguard 0.6.4
File Interpreter ABI Platform
harnessguard-0.6.4-py3-none-any.whl Python 3 none any Details

Total release size:2.0 MB

Release files / harnessguard-0.6.4.tar.gz

Download URL harnessguard-0.6.4.tar.gz
Size 2.0 MB
Tags Source
SHA-256 checksum
How to use checksums
1c0af4cc43ab1db7583a9b4696ccf1f33dac69cd559b29af7d45f8e56cba4e24
BLAKE2b-256 checksum
How to use checksums
c23eb88d96ceb8f34786d5ddbe3838a67b84263d62660b181c57aeb040132e63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / harnessguard-0.6.4-py3-none-any.whl

Download URL harnessguard-0.6.4-py3-none-any.whl
Size 36.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9b7bb03275c0d15a108ac10d9a6f94220d1c029dce8752a98ae75af7cb63122e
BLAKE2b-256 checksum
How to use checksums
cce3870fadd7a95f312e1f79ee4acc53854214f9bc3e022d1344ee458aaf1d81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.6.4 This release

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page