Repository navigation
RTP R-04 rates audit-log tampering at residual LOW and says _check_genesis_manifest 'refuses truncate-and-resume'. The exact R-04 scenario ('approve a model that wasn't approved')… (CR-A07-024) #383
Description
Wave 1 · theme D1-3: Revert, approval and GDPR erasure safety · highest severity High · 1 finding(s) · effort small
Summary
The trainer CI (which per access_control.md:122-124 holds FORGELM_AUDIT_SECRET) or any output-dir writer drops the trailing human_approval.rejected or model.reverted line and appends a forged decision or resumes. Under --require-hmac the forger must hold the secret; without it the forgery needs no secret at all. The R-04 cron verification exits 0, and the auditor relies on a LOW residual that was never accepted.
Primary finding
CR-A07-024 — RTP R-04 rates audit-log tampering at residual LOW and says _check_genesis_manifest 'refuses truncate-and-resume'. The exact R-04 scenario ('approve a model that wasn't approved') verifies with exit…
severity High · reachability default · intent contract-violation · confidence confirmed · independently confirmed · reproduced end to end
What happens. risk_treatment_plan.md:75-84 (TR :76-85) describes an adversary who has write access to audit_log.jsonl and rewrites entries 'to hide a deployment / approve a model that wasn't approved'. It rates the risk inherent Low x High = MED and residual Low x Low = LOW, so R-04 never needs an entry in the section 5 acceptance log. The residual rests only on ForgeLM mechanisms. No deployer-side control is listed: no write-once shipping and no off-host anchoring of the chain head. Against that adversary, every listed mechanism fails on a property that has already been verified false: (a) With no secret (the default), the chain and the genesis manifest are both unkeyed. This is the already-reported 'Default unkeyed chain lets any line after line 1 be edited and re-chained'. (b) With the secret set, the default forgelm verify-audit (the R-04 'cron' review cadence) accepts _hmac-stripped and unsigned lines (M-A07-001). (c) Tail truncation is undetected even with --require-hmac (M-A07-002). (d) Whole-record substitution (M5r1-A07-012) and fork splice (M5r1-A07-010) both verify clean. (e) The trainer principal holds the HMAC key (M5r1-A07-044). New evidence 1: the treatment text '_check_genesis_manifest refuses truncate-and-resume' holds only for truncate-to-zero. The guard fires only when the log is absent or empty (compliance.py:419-441). A partial truncation followed by a resume is accepted at write time, because log_event re-reads the truncated head under the lock (compliance.py:549-553), and the result verifies with require_hmac=True. New evidence 2: the R-04 description, reproduced end to end. A reviewer rejects the model. The rejection line is dropped from the tail. forgelm approve is then run as the reviewer, and forgelm verify-audit --require-hmac prints 'OK: 4 entrie…
Where.
docs/qms/risk_treatment_plan.md:84docs/qms/risk_treatment_plan.md:82docs/qms/risk_treatment_plan-tr.md:80docs/qms/risk_treatment_plan-tr.md:83forgelm/compliance.py:419-441forgelm/compliance.py:545-552forgelm/compliance.py:2396-2446forgelm/compliance.py:2449-2520forgelm/compliance.py:2523-2578docs/guides/iso_soc2_deployer_guide.md:309-315(same 'surfaces truncate-and-resume tampering' claim)
Evidence.
- Repro B (r04_truncate_resume.py): a 4-event keyed log is cut to 2 lines (evaluation.failed and model.reverted dropped). AuditLogger(run_id same).log_event('pipeline.completed') is ACCEPTED, then verify_audit_log(hmac_secret, require_hmac=True) returns VerifyResult(valid=True, entries_count=3). Repro A: a log truncated to zero followed by log_event raises ConfigError, so only that case is refused. r12_reject_erasure.sh: reject exits 0; approve is refused while the rejection is present; after `he…
Recommended fix. Re-rate the R-04 residual to at least MED (Low x High) and add R-04 to the section 5 acceptance log. Alternatively, list the deployer-side controls that actually bound it: real-time shipping to WORM/SIEM, recording entries_count and the last-line hash off-host after every run, always running --require-hmac, and keeping the secret away from the trainer principal. Replace 'refuses truncate-and-resume' with 'refuses to re-root an absent or empty log only'. Mirror both changes in the TR page.
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