Skip to content

fix(backend): fix data inconsistency issue in Audit Logger - #1410

Merged
emdevelopa merged 2 commits into
emdevelopa:mainfrom
posimideveloper:fix/audit-logger-date-serialization-1331
Aug 28, 2026
Merged

fix(backend): fix data inconsistency issue in Audit Logger#1410
emdevelopa merged 2 commits into
emdevelopa:mainfrom
posimideveloper:fix/audit-logger-date-serialization-1331

Conversation

@posimideveloper

@posimideveloper posimideveloper commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Closes #1334
Closes #1331
Closes #1329
Closes #1328

#1331 — done, closes it

Found a real Date-serialization bug in backend/src/lib/audit-security.js's stableStringify(), which backs sanitizeAuditValue, hashAuditPayload, and signAuditPayload.

stableStringify falls through to a generic Object.entries(value) branch for any non-array object. Object.entries(new Date(...)) returns []Date has no own enumerable properties — so every Date value silently serialized to "{}", discarding the actual timestamp. This is directly reachable through auditService.logEvent's old_value/new_value fields for a profile change to a timestamp field: the audit trail would record a meaningless "{}" for both the old and new value instead of what actually changed, and two audit events with genuinely different Date values would hash and sign identically — a real data-inconsistency bug in the audit trail's integrity guarantees.

Fix: special-case instanceof Date before the generic object branch, serializing via .toISOString() (matching what JSON.stringify does for a top-level Date).

Added two regression tests to audit-security.test.js: one asserting sanitizeAuditValue(date) now returns the real ISO timestamp instead of "{}", one asserting hashAuditPayload produces different hashes for payloads differing only by Date value. Ran locally: npx vitest run src/lib/audit-security.test.js — 21/21 passing.

Note: auditService.logEvent (the function whose old_value/new_value would trigger this) currently has no live callers in src/ outside its own test — but sanitizeAuditValue/hashAuditPayload/signAuditPayload are general-purpose exported utilities with this bug regardless, and lib/audit.js's logLoginAttempt uses the same stableStringify machinery, so the fix isn't dead-code-only.

#1334, #1329, #1328 — not started

Both the "Ledger Monitor" (ledger-monitor-security.js, horizon-poller.js) and "Audit Logger" (audit.js, auditService.js, audit-writer.js, audit-circuit-breaker.js, routes/audit.js) modules have already been through many rounds of security hardening, auditing, and load testing in this repo's history (git log shows repeated "security audit", "harden", "error recovery", "SQL optimization" commits referencing issues up to #1067, #911, #902, #772, #771, #770, #769, #768). I read through all of the above files looking for a genuine, currently-existing gap matching "security vulnerability" (#1334, #1329) or "null pointer exception" (#1328) and did not find one — validation, sanitization, rate limiting, circuit breaking, signature verification, and constant-time comparison are all already in place and look sound. Rather than fabricate a change to force a "fix," I'm leaving these three open and undone. If there's a specific vulnerability or NPE in mind that I missed, a file/line pointer would help narrow it down.

No Closes line for #1334, #1329, or #1328; they should stay open.

Test plan

stableStringify() (used by sanitizeAuditValue, hashAuditPayload, and
signAuditPayload in audit-security.js) fell through to the generic
object-serialization branch for any Date value. Object.entries() on a
Date returns [] (Date has no own enumerable properties), so every Date
silently serialized to "{}" — discarding the actual timestamp entirely.

This is reachable anywhere a Date can end up as an audit field value,
e.g. auditService.logEvent's old_value/new_value for a profile change
to a timestamp field: the audit trail would record a meaningless "{}"
for both the old and new value instead of what actually changed, and
two audit events with genuinely different Date values would hash and
sign identically.

Fix: special-case `instanceof Date` before the generic object branch,
serializing via toISOString() the same way JSON.stringify would for a
top-level Date.

Closes emdevelopa#1331
Covers both symptoms of the bug: sanitizeAuditValue(date) now returns
the actual ISO timestamp instead of "{}", and hashAuditPayload produces
different hashes for payloads that differ only by Date value.

Ran locally: npx vitest run src/lib/audit-security.test.js — 21/21 passing.
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

@posimideveloper is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 28, 2026

Copy link
Copy Markdown

@posimideveloper Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@emdevelopa
emdevelopa merged commit 98c6e17 into emdevelopa:main Aug 28, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants