fix(audit): frame hash inputs with TLV - #7492
Conversation
🔐 Codex Security Review
|
daa6f43 to
dcd3148
Compare
7cde393 to
e07cbeb
Compare
Signed-off-by: Jordan Mecom <jm@squareup.com>
e07cbeb to
53aa6be
Compare
wpfleger96
left a comment
There was a problem hiding this comment.
I reviewed 53aa6bed29e7ec06b2f6d94002563431ec23ed7e and didn’t find any blocking issues. The TLV framing covers the variable-length boundaries and distinguishes absent from present-empty fields, while the domain prefix separates the new encoding. I also checked that the legacy hash implementation is unchanged, new writes persist version 2 explicitly, and both read paths carry the stored version through verification. Keeping the database default at 1 preserves old-writer inserts during rollout without rewriting historical hashes.
CI at this head ran all 16 audit unit tests and all six PostgreSQL audit tests successfully. I also redirected the production v2 dispatch to legacy hashing in a disposable worktree and ran the full non-ignored audit package suite: both boundary regressions, the v2 digest pin, and the absent-versus-zero previous-hash case failed as expected. The mutation was discarded.
This approval is based on source review, the executed CI coverage, and that mutation check; I haven’t independently exercised a populated production-style rollout. The documented migration-before-writers/verifiers ordering still applies.
…c-agent-commit-identity * origin/main: fix(desktop): bound startup request bursts and recover quota refusals (#7790) fix(audit): frame hash inputs with TLV (#7492) fix(admin): allow cold storage worker DB startup (#7770) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…-dev * origin/main: fix(desktop): bound startup request bursts and recover quota refusals (#7790) fix(audit): frame hash inputs with TLV (#7492) fix(admin): allow cold storage worker DB startup (#7770) feat(relay): add admin HTTP routes for member restriction management (#7302) fix(relay): fire kick live side effects at convergence; persist target; fence re-add race with held lock (#7298) feat(relay): add atomic complete read-state snapshots (#7572) fix(desktop): register macOS badges for new and existing installs (#7783) fix(mobile): avoid opening empty threads on message tap (#7756) fix(workflows): make deletion persistent and retryable (#7735) fix(mobile): preserve thread replies through refresh failures (#7757) fix(mobile): keep iOS message menu actions responsive after rebuilds (#7758) fix(relay): exclude ephemeral activity from message quota (#7736) release: push gateway chart 0.3.1 (#7749) fix(push): label plaintext push gateway service as HTTP (#7717) Replace personal and internal data in desktop test fixtures (#7748) Add mobile VISION (#7710) fix(mobile): keep relay sessions stable during push lease updates (#7745) Signed-off-by: Tom Brow <tomb@block.xyz>
…n-surface * origin/main: docs(nip-fi): clarify federated identity amendments (#7803) fix(desktop): refresh channels after access-revoked closure (#7784) fix(desktop): bound startup request bursts and recover quota refusals (#7790) fix(audit): frame hash inputs with TLV (#7492) fix(admin): allow cold storage worker DB startup (#7770) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…-hardening * origin/main: docs(nip-fi): clarify federated identity amendments (#7803) fix(desktop): refresh channels after access-revoked closure (#7784) fix(desktop): bound startup request bursts and recover quota refusals (#7790) fix(audit): frame hash inputs with TLV (#7492) fix(admin): allow cold storage worker DB startup (#7770) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
NIP-FI admin disconnect/deny API implementation, rebased onto origin/main (c213d90) after main advanced past the original merge-base (77729ab). No buzz-relay production code changed by main's 3 new commits (#7770, #7492, #7790) — rebase is conflict-free. Squash of all commits from 2a42ddf through 360150d97: Production: - Deny-map JWT verifier and command installer (S4) - Disconnect endpoint and route wiring - Admin HTTP routes for deny/undeny, expiry TTL - WS connection admission: deny-map check wired in - Audio pre-writer send bounding (1s timeout policy) - nip_fi_session.rs: bounded pre-registration pairing sends - handler.rs MINOR: Ok(Ok(())) success check replaces is_err() Witnesses (Thufir round-5 required corrections): - R2: drain_terminal!() race witness (before_not_a_member_drain_terminal hook + cancel_race_test_hook; falsification: remove lifecycle_cancel() → frame-1 timeout RED) - F3: real admission → 48101 JOIN wire bytes → handle_huddle_liveness_req oracle → authoritative generation == wire generation - F4: valid future deadline + cancel-while-held (not already-expired); falsification: already-expired → hook timeout RED - F5: {"kinds":[13534]} REQ skips DB lookup, reaches after_req_permit_acquired; AUTH OK(true) check; real Postgres+Redis pools; canonical denial frame + 1008 close; zero global+channel refcounts asserted - F6: ENV_TEST_MUTEX synchronization for Config::from_env() - F7: 10s bounded consumer threads; entry-hook Drop guards - R1: reason-published/before-enqueue witness - F1/F2: LifecycleClosed transition primitives Evidence inventory corrections per Thufir's requirement: root raw cancels follow pairing_deny_terminal/auth_deny_terminal; audio pre-registration pairing sends direct denial/close; post-registration deny-set/expired paths send directly then raw-cancel; wrapper cancellation exists before AND after run(control).await. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
NIP-FI admin disconnect/deny API implementation, rebased onto origin/main (c213d90) after main advanced past the original merge-base (77729ab). No buzz-relay production code changed by main's 3 new commits (#7770, #7492, #7790) — rebase is conflict-free. Squash of all commits from 2a42ddf through 360150d97: Production: - Deny-map JWT verifier and command installer (S4) - Disconnect endpoint and route wiring - Admin HTTP routes for deny/undeny, expiry TTL - WS connection admission: deny-map check wired in - Audio pre-writer send bounding (1s timeout policy) - nip_fi_session.rs: bounded pre-registration pairing sends - handler.rs MINOR: Ok(Ok(())) success check replaces is_err() Witnesses (Thufir round-5 required corrections): - R2: drain_terminal!() race witness (before_not_a_member_drain_terminal hook + cancel_race_test_hook; falsification: remove lifecycle_cancel() → frame-1 timeout RED) - F3: real admission → 48101 JOIN wire bytes → handle_huddle_liveness_req oracle → authoritative generation == wire generation - F4: valid future deadline + cancel-while-held (not already-expired); falsification: already-expired → hook timeout RED - F5: {"kinds":[13534]} REQ skips DB lookup, reaches after_req_permit_acquired; AUTH OK(true) check; real Postgres+Redis pools; canonical denial frame + 1008 close; zero global+channel refcounts asserted - F6: ENV_TEST_MUTEX synchronization for Config::from_env() - F7: 10s bounded consumer threads; entry-hook Drop guards - R1: reason-published/before-enqueue witness - F1/F2: LifecycleClosed transition primitives Evidence inventory corrections per Thufir's requirement: root raw cancels follow pairing_deny_terminal/auth_deny_terminal; audio pre-registration pairing sends direct denial/close; post-registration deny-set/expired paths send directly then raw-cancel; wrapper cancellation exists before AND after run(control).await. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
NIP-FI admin disconnect/deny API implementation, rebased onto origin/main (c213d90) after main advanced past the original merge-base (77729ab). No buzz-relay production code changed by main's 3 new commits (#7770, #7492, #7790) — rebase is conflict-free. Squash of all commits from 2a42ddf through 360150d97: Production: - Deny-map JWT verifier and command installer (S4) - Disconnect endpoint and route wiring - Admin HTTP routes for deny/undeny, expiry TTL - WS connection admission: deny-map check wired in - Audio pre-writer send bounding (1s timeout policy) - nip_fi_session.rs: bounded pre-registration pairing sends - handler.rs MINOR: Ok(Ok(())) success check replaces is_err() Witnesses (Thufir round-5 required corrections): - R2: drain_terminal!() race witness (before_not_a_member_drain_terminal hook + cancel_race_test_hook; falsification: remove lifecycle_cancel() → frame-1 timeout RED) - F3: real admission → 48101 JOIN wire bytes → handle_huddle_liveness_req oracle → authoritative generation == wire generation - F4: valid future deadline + cancel-while-held (not already-expired); falsification: already-expired → hook timeout RED - F5: {"kinds":[13534]} REQ skips DB lookup, reaches after_req_permit_acquired; AUTH OK(true) check; real Postgres+Redis pools; canonical denial frame + 1008 close; zero global+channel refcounts asserted - F6: ENV_TEST_MUTEX synchronization for Config::from_env() - F7: 10s bounded consumer threads; entry-hook Drop guards - R1: reason-published/before-enqueue witness - F1/F2: LifecycleClosed transition primitives Evidence inventory corrections per Thufir's requirement: root raw cancels follow pairing_deny_terminal/auth_deny_terminal; audio pre-registration pairing sends direct denial/close; post-registration deny-set/expired paths send directly then raw-cancel; wrapper cancellation exists before AND after run(control).await. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
NIP-FI admin disconnect/deny API implementation, rebased onto origin/main (c213d90) after main advanced past the original merge-base (77729ab). No buzz-relay production code changed by main's 3 new commits (#7770, #7492, #7790) — rebase is conflict-free. Squash of all commits from 2a42ddf through 360150d97: Production: - Deny-map JWT verifier and command installer (S4) - Disconnect endpoint and route wiring - Admin HTTP routes for deny/undeny, expiry TTL - WS connection admission: deny-map check wired in - Audio pre-writer send bounding (1s timeout policy) - nip_fi_session.rs: bounded pre-registration pairing sends - handler.rs MINOR: Ok(Ok(())) success check replaces is_err() Witnesses (Thufir round-5 required corrections): - R2: drain_terminal!() race witness (before_not_a_member_drain_terminal hook + cancel_race_test_hook; falsification: remove lifecycle_cancel() → frame-1 timeout RED) - F3: real admission → 48101 JOIN wire bytes → handle_huddle_liveness_req oracle → authoritative generation == wire generation - F4: valid future deadline + cancel-while-held (not already-expired); falsification: already-expired → hook timeout RED - F5: {"kinds":[13534]} REQ skips DB lookup, reaches after_req_permit_acquired; AUTH OK(true) check; real Postgres+Redis pools; canonical denial frame + 1008 close; zero global+channel refcounts asserted - F6: ENV_TEST_MUTEX synchronization for Config::from_env() - F7: 10s bounded consumer threads; entry-hook Drop guards - R1: reason-published/before-enqueue witness - F1/F2: LifecycleClosed transition primitives Evidence inventory corrections per Thufir's requirement: root raw cancels follow pairing_deny_terminal/auth_deny_terminal; audio pre-registration pairing sends direct denial/close; post-registration deny-set/expired paths send directly then raw-cancel; wrapper cancellation exists before AND after run(control).await. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Hash new audit entries from a TLV buffer built with one-byte field tags, big-endian u64 byte lengths, and raw values. Absent optional fields are omitted; present empty values retain their tag and zero length. This prevents bytes from moving between fields without restricting object IDs or inferring boundaries from field contents.
Store an explicit
hash_version. Migration 0048 labels existing rows as version 1, and new writers use version 2. Historical hashes are unchanged and mixed-version chains verify. The legacy encoding retains its original ambiguity; TLV protects new entries. Apply the migration before deploying the updated writers and verifiers.Tests cover both boundary collisions, absent versus empty fields, stable digests, unknown versions, mixed-version chains, and stored-row tampering. All 16 audit and 128 database unit tests passed. The six PostgreSQL audit tests passed against both migrated and fresh schemas, and a populated-row migration check preserved the historical hash. Full
just cipassed.Related audit fixes: #4216 and #4249; issue #4173.