Skip to content

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

Open

Description

@cemililik

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.

Evidence.

  • key = hashlib.sha256(hmac_secret.encode() + run_id.encode()).digest() after only an if not run_id truthiness 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

No one assigned

    Labels

    area: complianceCode area: compliancebacklog: knownAlready tracked in docs/roadmapbugSomething isn't workingsecuritySecurity-relevantseverity: highWrong behaviour or a false claim users rely onsource: review-2026-10Found by the October 2026 code and documentation reviewwave: 1Roadmap wave 1: high severity, small effort

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions