Skip to content

fix(auditing): mask sensitive entity-diff values and add IAuditExempt opt-out - #1392

Merged
iammukeshm merged 1 commit into
mainfrom
fix/audit-sensitive-values
Sep 25, 2026
Merged

iammukeshm merged 1 commit into
mainfrom
fix/audit-sensitive-values

Conversation

@iammukeshm

Copy link
Copy Markdown
Member

Fixes #1389 (proposal by @marcelo-maciel), plus a second leak found while verifying it.

1. Sensitive values were stored in plain text

EntityDiffBuilder set IsSensitive for property names containing password/secret/token, but still wrote the real old/new values into the payload. PropertyChange's comment ("value already masked/hashed") was false, and JsonMaskingService only runs in the HTTP middleware. Identity's DbContext is audited, so PasswordHash and token columns landed in auditing."AuditRecords".

Now: sensitive values → "****" (null stays null, so set/cleared is still visible). Keywords: password, secret, token, apikey, connectionstring, securitystamp.

2. Per-entity opt-out: IAuditExempt

The marker interface from the issue, in Modules.Auditing.Contracts. The interceptor skips any entry whose entity implements it. Opt-in, so nothing changes by default. [NoAudit] is unrelated (HTTP activity only); the XML doc and .agents/rules/modules/auditing.md say so.

Behaviour change

Audit rows for sensitive properties now show **** instead of the value. Anyone who relied on seeing those values in the trail loses them. That's intended.

Tests

AuditingSaveChangesInterceptorTests (EF InMemory + capturing publisher): insert masking, update masking of old and new values, and exempt vs non-exempt entities in one save (with a positive control). All three fail before the fix. Auditing.Tests 66/66, auditing integration tests 48/48, build 0 warnings.

🤖 Generated with Claude Code

… opt-out

EntityDiffBuilder flagged password/secret/token properties as IsSensitive but
stored their old and new values verbatim, so every Identity write copied
PasswordHash and token columns into AuditRecords. Sensitive values are now
masked to "****" (null kept as null) before the payload leaves the
interceptor; keyword list aligned with JsonMaskingService.

Adds IAuditExempt (Contracts): entities implementing it are skipped by the
entity-change interceptor entirely, for data that must live in one table only.
[NoAudit] only covers HTTP activity auditing and never did this.

Fixes #1389.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@iammukeshm
iammukeshm merged commit 921be0e into main Sep 25, 2026
16 checks passed
@iammukeshm
iammukeshm deleted the fix/audit-sensitive-values branch September 25, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Entity audit trail has no per-entity opt-out: sensitive values are copied into AuditRecords

1 participant