Skip to content

Implement a tamper-evident, hash-chained activity/audit log #264

Description

@Lakes41

Difficulty: Expert
Type: Security

Background
The /activity page functions as the guild's audit log — the record admins rely on to confirm what happened (members joining/leaving, passes activating/expiring, guild settings changing). An audit log's value depends heavily on admins being able to trust that historical entries haven't been silently edited or deleted, whether by a bug, a compromised process, or a malicious insider with database access.

Problem
Nothing in the current design (mock in-memory data today, and any future durable Postgres storage from Issue #6) provides tamper evidence for the activity log — a direct database edit (or a bug in application code) could alter or delete historical entries with no way for an admin to detect it after the fact.

Expected outcome
Each activity log entry, when written, includes a cryptographic hash that incorporates the entry's own content plus the hash of the immediately preceding entry (a hash chain), so that altering or deleting any historical entry breaks the chain from that point forward in a way that's programmatically detectable. A verification endpoint/tool allows an admin (or automated check) to confirm the chain is intact, and to pinpoint exactly where it breaks if it doesn't.

Suggested implementation

  • Define the canonical serialization of an activity entry used for hashing (must be deterministic — e.g. explicit field ordering, not relying on object key iteration order).
  • On write, compute hash_n = SHA256(serialize(entry_n) + hash_{n-1}), storing hash_n alongside the entry; use a well-known constant (e.g. all-zeros) as hash_0's predecessor.
  • Add a verification routine that walks the stored chain and recomputes hashes, reporting the first index at which the recomputed hash diverges from the stored one (if any).
  • Expose this as an internal admin tool/API endpoint (e.g. /api/activity/verify or a CLI script) rather than necessarily a prominent end-user UI feature, since this is primarily an integrity/ops tool.
  • Consider (and explicitly document the trade-offs of) whether the chain's final/latest hash should be periodically anchored somewhere outside the mutable database (e.g. logged externally) to detect a full-database tamper/replace — this can be scoped out of the initial implementation but should be discussed in the design write-up.
  • This feature only makes sense once there is a persistent store for activity (mock in-memory data resets on restart anyway) — this should be built on top of Issue Add a server-wide role sync command for admins #6's durable storage mode, or clearly scoped to only apply when durable mode is active.

Acceptance criteria

  • New activity entries are written with a hash that deterministically depends on their content and the previous entry's hash.
  • A verification routine correctly reports "chain intact" for an untampered log.
  • A test that directly mutates a stored historical entry (simulating a bypass of the application layer) causes verification to correctly detect and localize the break.
  • The design document/PR description explicitly addresses (even if only to defer) the "what if the whole chain is replaced" anchoring problem.
  • This feature is gated to durable storage mode (or otherwise clearly scoped) with mock mode behavior unchanged.
  • Tests and pnpm typecheck pass.

Likely affected files/directories
apps/dashboard/lib/storage/ (activity write path, building on Issue #6), new verification module/endpoint, apps/dashboard/app/activity/ (optional integrity indicator in UI).

Metadata

Metadata

Assignees

Labels

GrantFox OSSGrantFox Open Source Sponsorship program tagMaybe RewardedIssue may qualify for a reward upon successful completion per campaign rulesOfficial Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewardsarchitectureStructural / design-level changefeatureNew feature, enhancement, or functional additionsecuritySecurity-related fix, hardening, audit, or vulnerability remediation

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions