Repository navigation
Hostile JSON in audit logs, sidecars, Annex IV, pipeline or integrity files crashes the verifiers with a raw traceback (exit 1, no envelope) instead of the exit-6 verdict (CR-A07-015) #379
Description
Wave 1 · theme D1-2: Audit chain, integrity manifest and verifier robustness · highest severity High · 1 finding(s) · effort small
Summary
Set line 2's run_id to 5, or its _hmac to 'é'*64, then run forgelm verify-audit --require-hmac log --output-format json with the secret: EXIT=1, stdout empty, stderr ends with 'AttributeError: 'int' object has no attribute 'encode'' or 'TypeError: comparing strings with non-ASCII characters is not supported'. Replace the manifest with '[]' and run without a secret: EXIT=1 with AttributeError: 'list' object has no attribute 'get'. corroborate_pipeline_stage_census raises the same three exceptions.
Primary finding
CR-A07-015 — Hostile JSON in audit logs, sidecars, Annex IV, pipeline or integrity files crashes the verifiers with a raw traceback (exit 1, no envelope) instead of the exit-6 verdict
severity High · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end · already tracked: KNOWN-OPEN VERIFY-UNCAPPED-READ — F-W20260729-VERIFY-UNCAPPED-READ deferral row (owner S5) docs/roadmap/risks-and-decisions.md:263
What happens. The verify-* readers trust the types and shape of attacker-written JSON and catch only narrow classes (FileNotFoundError, IsADirectoryError, JSONDecodeError, UnicodeDecodeError, OSError). _verify_hmac_for_entry calls run_id.encode() and compare_digest on untyped fields (compliance.py:2429, 2439); _verify_genesis_manifest calls .get on a non-dict (2479; writer twin 420); the chain walk and _parse_authenticated_entries miss RecursionError and the >4300-digit ValueError (2470, 2544, 3377); _annex_iv.py:106-113 and _model_integrity.py:82-86 lack RecursionError; _pipeline_evidence.py misses ValueError (371-396, 579-604) and NUL in realpath (239); expected_hash[:16] raises TypeError (compliance.py:2089). No dispatcher handler exists (_dispatch.py:113-122), so Python exits 1.
Where.
forgelm/compliance.py:2439(compare_digest on an untyped tag)forgelm/compliance.py:2439(confirmed)forgelm/compliance.py:2470-2480(manifest json.load; .get on a non-dict)forgelm/compliance.py:2749forgelm/compliance.py:410-420(writer twin)forgelm/compliance.py:3445-3456forgelm/cli/subcommands/_verify_annex_iv.py:157(call) and :275 (call)docs/reference/verify_audit.md:126docs/reference/library_api_reference.md:266forgelm/compliance.py:2429(confirmed)
Evidence.
key = hashlib.sha256(hmac_secret.encode() + run_id.encode()).digest()after only anif not run_idtruthiness check;_hmac_module.compare_digest(expected_tag, tag)with no type check on tag;pinned = manifest.get("first_entry_sha256")with no isinstance(manifest, dict).- All cases run with secret set and --output-format json: hmacint -> EXIT=1, stdout empty, 'TypeError: unsupported operand types(s) or combination of types: 'str' and 'int''; runidint -> EXIT=1 'AttributeError: 'int' object has no attribute 'encode''; manlist ('[]' manifest) -> EXIT=1 'AttributeError: 'list' object has no attribute 'get''; hugeint -> EXIT=1 'ValueError: Exceeds the limit (4300 digits)...'; deep (200000-deep array) -> EXIT=1 'RecursionError: maximum recursion depth exceeded while…
- repro_d_audit.py D3: _hmac set to 'é'*64 gives exit 1, 'TypeError: comparing strings with non-ASCII characters is not supported'. D3b: _hmac set to 12345 gives exit 1 TypeError. D4: run_id set to 7 gives exit 1, AttributeError 'int' object has no attribute 'encode'. Separately (shell run D5), a valid log with audit_log.jsonl.manifest.json set to '[]' gives exit 1 AttributeError; a non-UTF-8 sidecar gives exit 1 UnicodeDecodeError; a deeply nested sidecar gives exit 1 RecursionError. All cases w…
Recommended fix. Validate types before use. A non-str or empty run_id on a tagged line, or a non-str or non-64-hex _hmac, should return an integrity VerifyResult. A non-dict manifest should return 'manifest present but malformed' (integrity), on both the verify side and the writer guard. Optionally wrap the chain walk so any unexpected exception becomes AUDIT_FAILURE_INTEGRITY and is never a crash.
Acceptance criteria
- A regression test reproduces the failure scenario and asserts the corrected behaviour.
- Documentation listed above is corrected in English and in its Turkish mirror in the same PR.
- Every finding in this issue is resolved or explicitly closed with a reason.
Found by the October 2026 ForgeLM code and documentation review against commit cab2947. Code links point at that commit; line numbers may have moved since. Finding IDs (CR-…, DOC-…, TECH-…) are stable references for this backlog.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity