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
Points: 200
Category: SECURITY
Summary
GlobalExceptionFilter'smaskBody()(src/common/filters/global-exception.filter.ts) redacts request-body fields by exact key match againstSENSITIVE_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/LoginDtoinsrc/modules/auth/auth.controller.tsusepasswordHash(notpassword) for the raw credential value; OTP verification DTOs commonly usecode, nototp; API key creation accepts asecretfield (see the related webhook/API-key secret issues), notsecretKey; 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/signupor/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 oflogPayload.body, sincepasswordHash(andcode,secret, etc.) simply don't match any entry inSENSITIVE_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
SENSITIVE_FIELDSto 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.password,secret,token,otp,code) so a newly-added sensitive field doesn't require remembering to update this list by hand.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, usingpasswordHash)Acceptance Criteria
SENSITIVE_FIELDS(or its replacement matching strategy) covers every actual sensitive field name in use, not just the original fourpasswordHashis redacted in the exception-filter's log outputPoints: 200
Category: SECURITY