Skip to content

[Wave 200pts] SECURITY: GlobalExceptionFilter's sensitive-field redaction list doesn't match the actual field names used by auth/API DTOs, leaking credentials into logs #1157

Description

@portableDD

Summary

GlobalExceptionFilter's maskBody() (src/common/filters/global-exception.filter.ts) redacts request-body fields by exact key match against SENSITIVE_FIELDS = new Set(['password', 'otp', 'totpCode', 'secretKey']) before logging the request body on any thrown exception. However, the actual DTOs used elsewhere in the codebase use different field names: SignupDto/LoginDto in src/modules/auth/auth.controller.ts use passwordHash (not password) for the raw credential value; OTP verification DTOs commonly use code, not otp; API key creation accepts a secret field (see the related webhook/API-key secret issues), not secretKey; and refresh-token/2FA flows carry their own differently-named sensitive fields not covered by this list at all.

Why This Matters

Because the redaction check is an exact-string match against a small, stale list, any request to /auth/signup or /auth/login (or other endpoints using differently-named credential fields) that throws an exception — a validation error, a downstream service failure, anything routed through this global filter — will log the raw, unredacted credential value as part of logPayload.body, since passwordHash (and code, secret, etc.) simply don't match any entry in SENSITIVE_FIELDS. Given this filter's own explicit purpose is to prevent exactly this kind of leak, having its redaction list silently out of sync with the DTOs it's supposed to protect is a real, live credential-logging vulnerability.

What Needs to Be Done

  • Update SENSITIVE_FIELDS to include every actual sensitive field name used across the codebase's DTOs: passwordHash, password, code (OTP), secret (API keys/webhooks), totpCode, refreshToken, backupCode, and any others surfaced by an audit of @Body() DTOs across auth/otp/api-keys/webhooks.
  • Consider switching from an exact-match Set to a case-insensitive substring/regex match (e.g. any key containing password, secret, token, otp, code) so a newly-added sensitive field doesn't require remembering to update this list by hand.
  • Add a test asserting that a thrown exception on a request containing passwordHash (and the other newly-added fields) results in a redacted value in the resulting log payload.

Key Files

  • src/common/filters/global-exception.filter.ts (SENSITIVE_FIELDS, maskBody)
  • src/modules/auth/auth.controller.ts (SignupDto/LoginDto, using passwordHash)

Acceptance Criteria

  • SENSITIVE_FIELDS (or its replacement matching strategy) covers every actual sensitive field name in use, not just the original four
  • A test proves a request body containing passwordHash is redacted in the exception-filter's log output
  • Future new sensitive fields are covered by a pattern-based match rather than requiring a manually-maintained exact list, or the list is clearly documented as needing manual upkeep with a test that fails if a known sensitive DTO field is missing from it

Points: 200
Category: SECURITY

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions