Releases: amurlaniakea/agent-harness-defense
Releases · amurlaniakea/agent-harness-defense
Release list
v0.2.0 — IFC propagation (dual-lattice, plan-first)
Changelog
All notable changes to agent-harness-defense are documented here. The format
is loosely based on Keep a Changelog and the
project adheres to Semantic Versioning.
[0.2.0] — 2026-08-29
Breaking changes
run_admissionnow requires aPlan(declarative) as its third argument;
the v0.1proposed_filesparameter is removed. Themissionstring is now
part of thePlan. Migration:# v0.1 run_admission(repo, label, "mission text", proposed_files=[...]) # v0.2 run_admission(repo, label, Plan(mission="mission text", steps=[...]))
ahd run PATHis nowahd run REPO --plan PATH(YAMLPlan). The plan is
the unit of admission, not the on-disk materialized state.
Added
- Dual-lattice IFC (confidentiality + integrity) per arXiv:2608.27234 (SPA,
Girrens & Wang).SourceTag,Label(componentwise join: confidentiality
= max, integrity = min so "taint does not wash"),PlanStep,Plan,
PlanVerdict,evaluate_plan,plan_from_yamlin
agent_harness_defense.ifc. - Propagation by
depends_on(control-flow) andvalue_source(data-flow):
awritedriven by an UNTRUSTEDreadinherits UNTRUSTED integrity and is
denied (no-upgrade); a SECRET value written to a public sink is denied
(no-downgrade). Both axes reported separately. - Reads classified by path (
_classify_read_path): repo text → UNTRUSTED,
system paths → SYSTEM. Pure, no filesystem access. INCIDENT_REPORT_INJECTIONscenario (AC-EVAL-1) +assert_plan_matches_ materializedguard against Plan↔materialized drift.- 23 tests (was 6 v0.1): 7 v0.2 IFC (3 lattice + 4 propagation) + 3 conftest
- 2 false-positive guards + 7 v0.1-adapted (3 IPI + 2 monitor + 1 regression
- 1 loop-state). The v0.1 regression guard now monkey-patches
evaluate_planto prove the eval is non-vacuous.
Changed
- The v0.1 keyword heuristic (
ESCALATION_TRIGGERS+LoopStateMonitor) is
now a SECOND signal (flagged_by_keyword/cross_iteration_signal), not
the admission decision. The IFC verdict is authoritative. InstructionLeveland_level_of_fileremoved (superseded by the
dual-lattice inifc.py).
Closed limitations (see KNOWN_ISSUES.md §1)
- AC-IFC-1 (lattice enforcement, both axes)
- AC-IFC-2 (data-flow propagation)
- AC-IFC-3 (control-flow propagation, both axes)
- AC-IFC-4 (false-positive guards)
- AC-IFC-5 (no-regression: v0.1 scenarios adapted, teeth guard added)
- AC-IFC-6 (eval is not vacuous: v0.1 missed AC-EVAL-1, v0.2 catches)
- AC-IFC-7 (offline, <1s/test)
Remaining (v0.3, see ROADMAP.md)
- Label-preserving persistence between iterations (arXiv:2608.27234
§label-preserving). - AgentDojo / AgentDojo-MQ benchmark wiring.
- The 6 real coding-agent harnesses from arXiv:2608.27299.
[Unreleased] — v0.1.0 (2026-08-28)
First public release. Open admission-layer defense for LLM agent harnesses.
Added
run_admission()with forbidden-path quarantine gated by a cross-iteration
escalation monitor (arXiv:2608.27141).LoopStateMonitorretaining state across loop iterations; observes ALL
untrusted repo text (planted input) separately from the admission decision.InstructionLevelenum and_level_of_file()for provenance of the
escalation decision (full label propagation is roadmap work; see
KNOWN_ISSUES.md§1 andROADMAP.md).- CLI:
ahd run PATHandahd eval. - Bundled adversarial scenarios re-modeling the public
Signetry/evalIPI
corpus:ipi.readme_deploy_and_exfilandipi.claude_md_scope_expansion.
The agent'sobey()step WRITES the malicious artifacts to disk so the eval
exercises the real defense. - Three independent guard rails proving the eval is non-vacuous:
- Teeth assert in
test_admission.py— fails withSCENARIO INCOMPLETE
ifobey()does not materialize the attack artifact. - Regression guard in
test_eval_catches_regression.py— a defense that
admits the forbidden artifact reportstrust_boundary_clean=False. - Monitor signal pins in
test_monitor_signal.py— the cross-iteration
monitor's signal is asserted at concrete values; the planted-input
invariant is verified by re-introducing the original bug and seeing the
test fail withREGRESSION:.
- Teeth assert in
Security
AGPL-3.0-or-laterlicense, verbatim text from
https://www.gnu.org/licenses/agpl-3.0.txt(the legal body from the FSF
Copyright (C) 2007 Free Software Foundationline onwards is byte-identical,
658 lines,diffempty). The author attribution is added as an FSF-style
header notice (the pattern recommended in the license's own "How to Apply
These Terms" section).- SPDX headers in every
.pysource file underagent_harness_defense/and
tests/. gitleaksscan in CI to catch accidental secret leaks.
CI / infra
pip install -e .[dev]verified on a clean runner (/tmp/ahd-clean):ruff check .→ All checks passed.ruff format --check .→ 12 files already formatted.pytest→ 6 passed.bandit -r agent_harness_defense -ll→ Low: 0, Med: 0, High: 15
(legitimate subprocess usage inadmission.pyforgit rev-parseand
git diff --stat; non-fatal with-ll).
gitleaks/gitleaks-action@v2withfetch-depth: 0(shallow clones break
the action's diff scan).[tool.hatch.metadata] allow-direct-references = trueso theevalextra
(which uses a direct git URL forsignetry-eval) installs without
ERROR: Direct references are not allowed.
Known limitations (see KNOWN_ISSUES.md for the full list)
- Taint propagation is NOT implemented. The
taintfield in
AdmissionReportrecords each file's label for provenance but does not
propagate labels across data/control flows. The direction is SPA
(arXiv:2608.27234); seeROADMAP.md. llm-guardis optional ([detect]extra) and not yet wired into
run_admission. It is offered as a second signal for callers who want it.- Cross-iteration state retention is the caller's responsibility. The CLI
does not drive a real agent loop; the harness that integrates
run_admissionmust reuse the sameLoopStateMonitorinstance. - Eval is narrow. Only the two IPI scenarios are re-modeled; the
skill_poisonandminjaSignetry scenarios and the 6 real coding-agent
harnesses from arXiv:2608.27299 are roadmap work.
Audits
Two independent external audits (Claude) on 2026-08-28:
- Round 1 flagged that the original eval was vacuous (the
obey()step
was missing) and that the README claimed taint propagation that did not
exist. Both fixed in the initial round of commits: port the real Signetry
obey(), add the teeth assert, document the v0.1 scope honestly in
KNOWN_ISSUES.md. - Round 2 flagged (a) a regression introduced by the
proposed_files
refactor — the cross-iteration monitor was scanning only the agent's
output, so the signal came from a coincidental substring in the agent's
output rather than from the planted injection; (b)pip install -e .[dev]
failed on a clean runner for three independent reasons (hatchling direct
references,gitleaksnot being a pip package,banditexiting 1 on
legitimate Low-severity findings); (c) the LICENSE lost its author
attribution when the verbatim swap removed it. All three fixed in commits
37e4b44,693de48, andd05723c.