fix(core): Stop logging password reset token values (#29405)

Co-authored-by: Garrit Franke <32395585+garritfra@users.noreply.github.com>
This commit is contained in:
Itay 2026-05-06 17:02:22 +03:00 committed by GitHub
parent d6cc3bedd1
commit bc8d196931
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 4 deletions

View File

@ -1,3 +1,4 @@
import type { Logger } from '@n8n/backend-common';
import type { GlobalConfig } from '@n8n/config';
import { Time } from '@n8n/constants';
import type {
@ -39,9 +40,10 @@ describe('AuthService', () => {
const invalidAuthTokenRepository = mock<InvalidAuthTokenRepository>();
const mfaService = mock<MfaService>();
const license = mock<License>();
const logger = mock<Logger>();
const authService = new AuthService(
globalConfig,
mock(),
logger,
license,
jwtService,
urlService,
@ -830,6 +832,19 @@ describe('AuthService', () => {
});
describe('resolvePasswordResetToken', () => {
const expectTokenNotLogged = (token: string) => {
const allLogCalls = [
...logger.debug.mock.calls,
...logger.info.mock.calls,
...logger.warn.mock.calls,
...logger.error.mock.calls,
];
for (const call of allLogCalls) {
const serialized = JSON.stringify(call);
expect(serialized).not.toContain(token);
}
};
it('should not return a user if the token in invalid', async () => {
const resolvedUser = await authService.resolvePasswordResetToken('invalid-token');
expect(resolvedUser).toBeUndefined();
@ -867,6 +882,31 @@ describe('AuthService', () => {
const resolvedUser = await authService.resolvePasswordResetToken(token);
expect(resolvedUser).toEqual(user);
});
it('should not include the raw token in any log entry when the token is malformed', async () => {
const malformedToken = 'this-is-not-a-valid-jwt';
await authService.resolvePasswordResetToken(malformedToken);
expectTokenNotLogged(malformedToken);
});
it('should not include the raw token in any log entry when the token is expired', async () => {
const expiredToken = authService.generatePasswordResetToken(user, '-1h');
await authService.resolvePasswordResetToken(expiredToken);
expectTokenNotLogged(expiredToken);
});
it('should not include the raw token in any log entry when the referenced user is missing', async () => {
userRepository.findOne.mockResolvedValueOnce(null);
const validToken = authService.generatePasswordResetToken(user);
await authService.resolvePasswordResetToken(validToken);
expectTokenNotLogged(validToken);
});
});
describe('invalidateToken', () => {

View File

@ -385,9 +385,9 @@ export class AuthService {
decodedToken = this.jwtService.verify(token);
} catch (e) {
if (e instanceof TokenExpiredError) {
this.logger.debug('Reset password token expired', { token });
this.logger.debug('Reset password token expired');
} else {
this.logger.debug('Error verifying token', { token });
this.logger.debug('Error verifying token');
}
return;
}
@ -400,7 +400,7 @@ export class AuthService {
if (!user) {
this.logger.debug(
'Request to resolve password token failed because no user was found for the provided user ID',
{ userId: decodedToken.sub, token },
{ userId: decodedToken.sub },
);
return;
}