fix: Opus 4.8 bug sweep (timelock data-loss, fountain DoS, cat-mode decode, GIF tamper index) - #201
Merged
Merged
Conversation
Rust crypto core: - Fountain decoder rejected nothing on geometry mismatch: a droplet with an out-of-range block index or wrong-width data panicked (OOB index / abort in wasm = DoS) via the public PyO3/wasm add_droplet. Added a geometry guard so such droplets are ignored, plus regression tests. - timing_encode: base_delay + jitter + value could overflow u16; use saturating arithmetic. Python: - decode_gif: legacy ML-KEM-1024 GIFs were un-decodable — expected_lengths and mac_sizes omitted 1715/1747 (and MAC'd 1723/1755) that unpack_manifest accepts. Added them to match the pattern used for every other mode. - nonce: generate_for_transfer with empty context produced a nonce identical to generate() (GCM reuse) and bypassed the reuse guard. Domain-separated it and added a (counter, context) reuse guard. +regression tests. - size_normalizer: explicit size_class validation ignored the 8-byte length header, passing validation then crashing in pad_to_size_class. Mirror the auto-select branch. Cat mode (web video protocol): - refine_bp collapsed a correct preamble-derived blink period to a far smaller value on compressed (VP9/camera) video, because transition artifacts polluted the single-blink median — inflating the decoded bitstream ~1.5x and breaking decode. Added a plausible-band filter and a clamp to the reliable preamble estimate. Verified against a realistic VFR-WebM ffmpeg pipeline; no regression on clean video. Rust suites (crypto_core 180, rust_crypto 67) and touched Python tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pen reporting
timelock_duress (CRITICAL data loss): memory-hard puzzles were permanently
undecryptable — create_puzzle ran a counter-mixed SHA-256 chain over
iterations//1000 rounds, but solve_puzzle had no memory-hard branch and
puzzle_data didn't carry the flag, so the target could never be reproduced.
Now puzzle_data carries a 1-byte use_memory_hard flag (40->41 bytes, backward
compatible: legacy 40-byte puzzles parse as standard) and solve_puzzle mirrors
the construction. Added a real round-trip regression test (>=1000 iters; the
old test used 500 -> 0 rounds and never exercised the bug).
web_demo/app.py (concurrency): the four download_tokens[...] = {...} inserts
ran without download_tokens_lock while cleanup_old_files() iterates the dict
under that lock on every request (Flask threaded), so a concurrent insert could
raise "dictionary changed size during iteration". Wrapped all four in the lock.
env_safety: _check_macos_debugger called report.add_warning(), which doesn't
exist — the AttributeError was swallowed by the caller's broad except, silently
disabling the macOS ptrace detection. Use add_risk(Risk(...)).
deadmans_switch_cli: cmd_renew computed the deadline from checkin_interval only,
dropping grace_period_seconds (which save() includes), so renew silently
shortened the window and the switch could fire early. Add the grace period.
forensic_cleanup: _clean_thumbnails and clean_clipboard reported success=True
even after recording an error — for a cleanup feature, masking failure is the
dangerous direction. Report success based on whether an error occurred.
metadata_obfuscation: pad_frame_count raised an opaque IndexError on frames[0]
for an empty frame list; raise a clear ValueError instead.
air_gap: clarified (docstring only) that air_gapped is intentionally vacuously
true and callers must consult `unknown` — a flagged "fail-open" was actually
deliberate, tested behavior; reverted the logic change.
Touched-module tests pass (timelock+air_gap 54, env/forensic/metadata/deadman 59).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…frames The valid-frame path recorded tamper_report.record(idx + 1, ...) (the QR-list position) while the invalid-frame path used actual_frame_idx (the true GIF frame index from qr_frame_indices). When stego extraction skips unreadable frames the two diverge, so the per-frame tamper timeline mixed two index spaces. Use actual_frame_idx consistently; also align the ratchet-fail verbose log to the same index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cross-cutting correctness/security bug sweep across the Rust crypto core, Python decode pipeline, and cat-mode web video protocol. 3 commits, +286/-55 across 14 files. Touched-module test suites pass (crypto_core 180, rust_crypto 67, plus Python timelock/air_gap/env/forensic/metadata/deadman suites).
Highlights
CRITICAL — timelock_duress data loss: memory-hard puzzles were permanently undecryptable (
solve_puzzlehad no memory-hard branch and the flag wasn't carried).puzzle_datanow carries a 1-byteuse_memory_hardflag (40→41 bytes, backward compatible) andsolve_puzzlemirrors the construction. Added a real round-trip regression test.Rust fountain decoder DoS: a droplet with an out-of-range block index or wrong-width data panicked (OOB / wasm abort) via the public PyO3/wasm
add_droplet. Added a geometry guard + regression tests. Also madetiming_encodeuse saturating arithmetic (u16 overflow).decode reliability:
decode_gif: legacy ML-KEM-1024 GIFs were un-decodable (missing 1715/1747 length+MAC sizes); also fixed tamper-report frame-index mixing two index spaces.refine_bp: collapsed a correct blink period on compressed (VP9/camera) video, inflating the bitstream ~1.5x. Added a plausible-band filter + clamp.other fixes: nonce GCM-reuse via empty context (domain-separated + reuse guard), web_demo
download_tokensconcurrency (missing lock),env_safetymacOS debugger detection silently disabled (wrong method), deadman's-switch renew dropping grace period, forensic_cleanup fail-open success reporting, size_normalizer validation bypass, metadata_obfuscation clearer error.🤖 Generated with Claude Code