Skip to content

Repository files navigation

HarnessGuard

A zero-cost, offline static analyzer for AI-agent orchestration code.

HarnessGuard finds security and reliability mistakes where agents, tools, state, and control loops are wired together. It never calls an LLM, never uploads code, and never executes the project it scans.

Status: working alpha MVP. Findings are review signals, not proof of exploitability.

The problem

The recurring failures reported across agent frameworks are not only model failures. They are ordinary engineering defects amplified by autonomous tools:

  • agents loop until recursion or budget exhaustion;
  • model-controlled text reaches shell, eval, files, or URLs;
  • unsafe checkpoints deserialize attacker-controlled state;
  • one compromised agent delegates to another without authorization;
  • concurrent agents overwrite shared state;
  • waits and HTTP calls hang without deadlines;
  • prompts, environment variables, and tool output leak into logs;
  • broad tool and filesystem permissions multiply blast radius.

Existing tools mainly red-team live models, benchmark prompt injection, or scan MCP components. They tell you how a running agent behaves, not how your harness was built. The defects above live in the harness source and configuration, and they are reviewable before anything runs.

The solution

HarnessGuard scans agent orchestration code before execution, fully locally. Python gets AST-aware checks. JSON, JSONC, YAML, TOML, INI, environment, Markdown, and text files get conservative line-level checks. Large, generated, dependency, and binary files are skipped. No imported project modules are loaded.

Every finding is a deterministic, reviewable signal: rule ID, severity, file, line, and snippet. Findings stream as text or structured JSON and map directly into GitHub code scanning via SARIF.

Why HarnessGuard

  • Zero cost and offline. No runtime dependencies, no endpoint, no token, no account, no paid API. Runs on Python 3.10+ anywhere, including air-gapped environments.
  • Deterministic. No LLM in the loop means identical output for identical input. Every run is reproducible and CI-friendly.
  • Safety by design. It reads source and configuration only. It never executes the project it scans and never uploads code.
  • Built for the harness, not the model. It targets how agents, tools, state, and control loops are wired together, the layer most tooling ignores.
  • CI-native. A least-privilege GitHub Actions workflow is included. SARIF uploads appear in GitHub code scanning when code-security upload is available.
  • Safe to adopt. Baselines let you ship the scanner into an existing project without failing on old findings; changed findings reappear.
  • Rule IDs are stable API. New IDs are added over time; released IDs never silently change meaning.

Features

The 30 built-in checks

ID Severity Check
HG001 critical Dynamic eval
HG002 critical Dynamic exec
HG003 critical Dynamic shell command
HG004 high Unsafe subprocess arguments
HG005 critical Pickle/dill deserialization
HG006 high YAML load without SafeLoader
HG007 critical Dangerous deserialization enabled
HG008 critical Secret-like literal
HG009 high Whole environment sent to model/log
HG010 critical Environment secrets imported into serializer
HG011 high LangGraph-style invocation without recursion limit
HG012 high CrewAI agent without max_iter
HG013 critical Zero, negative, or huge execution budget
HG014 high Automatic delegation without a budget
HG015 critical Agent code execution enabled
HG016 medium Human approval explicitly disabled
HG017 high Wildcard tool permission
HG018 high Admin/root/all-access capability grant
HG019 medium HTTP request without timeout
HG020 high Blocking wait without timeout
HG021 medium Thread join without timeout
HG022 high Unbounded retry/agent loop
HG023 medium Async shared-state mutation without visible lock
HG024 high Tool parameter used directly as file path
HG025 high Tool parameter used directly as URL
HG026 high Root/full-filesystem access
HG027 medium Untrusted data concatenated into prompt
HG028 medium Raw agent-output handoff
HG029 high Sensitive prompt/message logging
HG030 high TLS verification disabled

List rules from the CLI:

harnessguard --list-rules

Outputs and CI

harnessguard . --format text
harnessguard . --format json --output report.json
harnessguard . --format sarif --output harnessguard.sarif
harnessguard . --severity medium

Exit codes: 0 no finding at/above threshold; 1 policy failed; 2 scanner/config/read error.

Quickstart

Requires Python 3.10+ and no runtime dependencies. For the full CLI reference, configuration options, baselines, output formats, and CI setup, see docs/USAGE.md.

Install and run

python -m pip install -e .
harnessguard path/to/agent-project

Without installation:

PYTHONPATH=src python -m harnessguard path/to/agent-project

Windows PowerShell:

$env:PYTHONPATH="src"
python -m harnessguard .

Scan the intentionally vulnerable example:

$env:PYTHONPATH="src"
python -m harnessguard examples/vulnerable_harness.py --severity high

Configuration and baselines

Create .harnessguard.json in the scan root:

{
  "exclude": ["generated/*", "vendor/*"],
  "ignore": ["HG029"],
  "max_file_size": 1000000
}

Suppress one line inline in text/config files by including harnessguard: ignore. Prefer project-level rule ignores only after a security review.

Adopt the scanner in an existing project without failing on old findings:

harnessguard . --write-baseline .harnessguard-baseline.json
harnessguard . --baseline .harnessguard-baseline.json

Fingerprints include rule, path, line, and snippet; changed findings reappear.

CI

The included workflow at .github/workflows/harnessguard.yml scans on every push and pull request with least-privilege permissions and uploads SARIF to GitHub code scanning.

Detection model

Python gets AST-aware checks. JSON, JSONC, YAML, TOML, INI, environment, Markdown, and text files get conservative line-level checks. Large, generated, dependency, and binary files are skipped. No imported project modules are loaded.

This MVP emphasizes high-signal local patterns and deliberately avoids claiming full taint analysis. A finding means "review this boundary." Future versions should add language-neutral data flow, framework adapters, dependency advisory matching, and policy-as-code.

Architecture

                         ┌──────────────────────────────┐
                         │   Config (.harnessguard.json) │
                         │  exclude · ignore · max_size  │
                         └──────────────┬───────────────┘
                                        │
                                        ▼
   ┌──────────────┐              ┌──────────────┐
   │   CLI (cli.py)│──args──────▶│  Scanner      │──walk + filter──▶ supported files
   │  --format     │              │  (scanner.py) │                   (.py/.json/.yaml/.toml/.env/.md/...)
   │  --severity   │              └──────┬───────┘
   │  --baseline   │                     │ read text (never execute, never import)
   └──────────────┘                     ▼
                          ┌─────────────────────────────┐
                          │       per-file analysis      │
                          │  Python → python_analyzer.py │  AST-aware (ast.NodeVisitor)
                          │  Text   → text_analyzer.py   │  line-level regex
                          └──────────────┬──────────────┘
                                         ▼
                              ┌──────────────────────┐
                              │  Rules (rules.py)     │  30 stable IDs + severity + fix
                              └──────────┬───────────┘
                                         ▼
                              ┌──────────────────────┐
                              │  Models (models.py)   │  Finding (fingerprint), Rule
                              └──────────┬───────────┘
                                         ▼
                     ┌──────────────────────────────────┐
                     │  Reporters (reporters.py)          │
                     │  text · json · sarif               │
                     └──────────────────┬───────────────┘
                                        ▼
                     exit code 0 / 1 / 2   +   baseline suppression (baseline.py)

How a scan works

  1. Discovery. The scanner walks the target file or directory, applies exclude globs and the file-size cap, and keeps only supported extensions and special names (Dockerfile, mcp.json, requirements.txt). No scanned project module is imported or executed.
  2. Analysis. Each supported file is read as text and analyzed twice when relevant: every file goes through the line-level text analyzer; .py files also go through the AST-aware Python analyzer.
  3. Rules. Both analyzers emit Finding objects from the single rule registry (rules.py), which assigns each check a stable ID, severity, category, message, and fix hint.
  4. Suppression. Rule-level ignores (config ignore), inline harnessguard: ignore, and baseline fingerprints are applied before findings are sorted and reported.
  5. Reporting. Findings render as human-readable text, JSON, or SARIF 2.1. The exit code is 0 when no finding meets the severity threshold, 1 when policy fails, and 2 on a scanner/config/read error.

The scanner has zero runtime dependencies and no network surface: the entire pipeline runs on the standard library, making it safe for laptops, pre-commit hooks, and air-gapped CI.

Roadmap

  1. Benchmark rules against real vulnerable and fixed framework examples.
  2. Add taint tracking from prompt/tool inputs to dangerous sinks.
  3. Add framework adapters for LangGraph, CrewAI, AutoGen, Semantic Kernel, PydanticAI, smolagents, and MCP.
  4. Add JavaScript/TypeScript and C# parsers without compromising offline use.
  5. Map checks to OWASP Agentic categories and published advisories in machine-readable metadata.
  6. Add safe autofix suggestions and reusable pre-commit integration.

Research evidence

Public reports demonstrate the pain:

Nearby tools include garak, PyRIT, AgentDojo, and Snyk Agent Scan. Their scopes differ: HarnessGuard's MVP is deterministic static scanning of orchestration code with no endpoint, token, account, or paid API.

Development

python -m pip install -e .
python -m unittest discover -s tests
harnessguard .

See CONTRIBUTING.md and SECURITY.md. Licensed under MIT.

About

HarnessGuard: a zero-cost, offline static analyzer that catches security and reliability flaws in AI agent orchestration code before it ever runs.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages