From 87bbe672fd23bb08885e8e13cce709370268493c Mon Sep 17 00:00:00 2001 From: Dobrunia Kostrigin <48620984+Dobrunia@users.noreply.github.com> Date: Thu, 29 Jan 2026 19:51:35 +0300 Subject: [PATCH 1/4] fix(grouper): filter oldPassword and newPassword in event payload --- workers/grouper/src/data-filter.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workers/grouper/src/data-filter.ts b/workers/grouper/src/data-filter.ts index 40a4acf9..65a956b3 100644 --- a/workers/grouper/src/data-filter.ts +++ b/workers/grouper/src/data-filter.ts @@ -44,6 +44,8 @@ export default class DataFilter { 'credentials', 'card[number]', 'password', + 'oldpassword', + 'newpassword', 'auth', 'access_token', 'accesstoken', From 16463dcb34f95e77810c7665040c22c0bcb0f802 Mon Sep 17 00:00:00 2001 From: Dobrunia Kostrigin <48620984+Dobrunia@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:09:23 +0300 Subject: [PATCH 2/4] chore: add more keys and update tests --- workers/grouper/src/data-filter.ts | 68 ++++++++++++++++++++--- workers/grouper/tests/data-filter.test.ts | 62 +++++++++++++++++++++ 2 files changed, 123 insertions(+), 7 deletions(-) diff --git a/workers/grouper/src/data-filter.ts b/workers/grouper/src/data-filter.ts index 65a956b3..031f6c83 100644 --- a/workers/grouper/src/data-filter.ts +++ b/workers/grouper/src/data-filter.ts @@ -36,19 +36,71 @@ export default class DataFilter { private filteredValuePlaceholder = '[filtered]'; /** - * Possibly sensitive keys + * Possibly sensitive keys (lowercase; keys are compared via key.toLowerCase()) */ private possiblySensitiveDataKeys = new Set([ - 'pan', + /** + * Authorization and sessions + */ + 'auth', + 'authorization', + 'access_token', + 'accesstoken', + 'token', + 'jwt', + 'session', + 'sessionid', + 'session_id', + /** + * API keys and secure tokens + */ + 'api_key', + 'apikey', + 'x-api-key', + 'x-auth-token', + 'bearer', + 'client_secret', 'secret', 'credentials', - 'card[number]', + /** + * Passwords + */ 'password', + 'passwd', + 'mysql_pwd', 'oldpassword', + 'old-password', + 'old_password', 'newpassword', - 'auth', - 'access_token', - 'accesstoken', + 'new-password', + 'new_password', + /** + * Encryption keys + */ + 'private_key', + 'ssh_key', + /** + * Payments data + */ + 'card', + 'cardnumber', + 'card[number]', + 'creditcard', + 'credit_card', + 'pan', + 'pin', + 'security_code', + 'stripetoken', + 'cloudpayments_public_id', + 'cloudpayments_secret', + /** + * Config and connections + */ + 'dsn', + /** + * Personal data + */ + 'ssn', ]); /** @@ -103,7 +155,9 @@ export default class DataFilter { */ const clean = value.replace(/\D/g, ''); - // Reset last index to 0 + /** + * Reset last index to 0 + */ this.bankCardRegex.lastIndex = 0; if (!this.bankCardRegex.test(clean)) { return value; diff --git a/workers/grouper/tests/data-filter.test.ts b/workers/grouper/tests/data-filter.test.ts index d0a4c3af..c9786f46 100644 --- a/workers/grouper/tests/data-filter.test.ts +++ b/workers/grouper/tests/data-filter.test.ts @@ -36,12 +36,46 @@ const sensitiveDataMock = { credentials: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67', 'card[number]': '5500 0000 0000 0004', password: 'bFb7PBm6nZ7RJRq9', + oldpassword: 'oldSecret123', + newpassword: 'newSecret456', + 'old-password': 'oldSecretHyphen', + old_password: 'oldSecretUnderscore', + 'new-password': 'newSecretHyphen', + new_password: 'newSecretUnderscore', auth: 'C4CA4238A0B923820DCC509A6F75849B', // eslint-disable-next-line @typescript-eslint/naming-convention access_token: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67', accessToken: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67', }; +/** + * Additional sensitive keys (newly added / previously uncovered) + */ +const additionalSensitiveDataMock = { + authorization: 'Bearer abc123', + token: 'token-value', + jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + session: 'sess_xyz', + session_id: 'sid_789', + api_key: 'sk_live_xxx', + bearer: 'Bearer token', + client_secret: 'client_secret_value', + passwd: 'passwd_value', + mysql_pwd: 'mysql_pwd_value', + private_key: '-----BEGIN PRIVATE KEY-----', + ssh_key: 'ssh-rsa AAAA...', + card: '4111111111111111', + cardnumber: '5500000000000004', + creditcard: '4111111111111111', + pin: '1234', + security_code: '999', + stripetoken: 'tok_xxx', + cloudpayments_public_id: 'pk_xxx', + cloudpayments_secret: 'secret_xxx', + dsn: 'postgres://user:pass@host/db', + ssn: '123-45-6789', +}; + describe('GrouperWorker', () => { const dataFilter = new DataFilter(); @@ -123,6 +157,34 @@ describe('GrouperWorker', () => { }); }); + test('should filter additional sensitive keys (authorization, token, payment, dsn, ssn, etc.) in context', async () => { + const event = generateEvent({ + context: additionalSensitiveDataMock, + }); + + dataFilter.processEvent(event); + + Object.keys(additionalSensitiveDataMock).forEach((key) => { + expect(event.context[key]).toBe('[filtered]'); + }); + }); + + test('should filter additional sensitive keys in addons', async () => { + const event = generateEvent({ + addons: { + vue: { + props: additionalSensitiveDataMock, + }, + }, + }); + + dataFilter.processEvent(event); + + Object.keys(additionalSensitiveDataMock).forEach((key) => { + expect(event.addons['vue']['props'][key]).toBe('[filtered]'); + }); + }); + test('should not replace values with keynames not in a list', async () => { const normalValue = 'test123'; const event = generateEvent({ From 0c853d3119703b7cf1a0e827ab2bd0a316d7565b Mon Sep 17 00:00:00 2001 From: Dobrunia Kostrigin <48620984+Dobrunia@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:12:26 +0300 Subject: [PATCH 3/4] chore: lint fix --- workers/grouper/tests/data-filter.test.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/workers/grouper/tests/data-filter.test.ts b/workers/grouper/tests/data-filter.test.ts index c9786f46..0ada27f1 100644 --- a/workers/grouper/tests/data-filter.test.ts +++ b/workers/grouper/tests/data-filter.test.ts @@ -28,8 +28,10 @@ function generateEvent({ context, addons }: {context?: Json, addons?: EventAddon } /** - * Example of object with sensitive information + * Example of object with sensitive information. + * Keys intentionally use snake_case/kebab-case to match data-filter list. */ +/* eslint-disable @typescript-eslint/naming-convention */ const sensitiveDataMock = { pan: '5500 0000 0000 0004', secret: 'D6A03F5C2E0E356F262D56F44370E1CD813583B2', @@ -43,13 +45,13 @@ const sensitiveDataMock = { 'new-password': 'newSecretHyphen', new_password: 'newSecretUnderscore', auth: 'C4CA4238A0B923820DCC509A6F75849B', - // eslint-disable-next-line @typescript-eslint/naming-convention access_token: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67', accessToken: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67', }; /** - * Additional sensitive keys (newly added / previously uncovered) + * Additional sensitive keys (newly added / previously uncovered). + * Keys intentionally use snake_case to match data-filter list. */ const additionalSensitiveDataMock = { authorization: 'Bearer abc123', @@ -75,6 +77,7 @@ const additionalSensitiveDataMock = { dsn: 'postgres://user:pass@host/db', ssn: '123-45-6789', }; +/* eslint-enable @typescript-eslint/naming-convention */ describe('GrouperWorker', () => { const dataFilter = new DataFilter(); From dcab26239b1a1269f83be2df12a1cb12d1ce64a8 Mon Sep 17 00:00:00 2001 From: Dobrunia Kostrigin <48620984+Dobrunia@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:25:42 +0300 Subject: [PATCH 4/4] fix(tests): rename sessionId to requestId in data-filter tests for clarity --- workers/grouper/tests/data-filter.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workers/grouper/tests/data-filter.test.ts b/workers/grouper/tests/data-filter.test.ts index 900488a5..4cb98807 100644 --- a/workers/grouper/tests/data-filter.test.ts +++ b/workers/grouper/tests/data-filter.test.ts @@ -219,7 +219,7 @@ describe('GrouperWorker', () => { const event = generateEvent({ context: { userId: uuidWithManyDigits, - sessionId: uuidUpperCase, + requestId: uuidUpperCase, transactionId: uuidNoDashes, }, addons: { @@ -234,7 +234,7 @@ describe('GrouperWorker', () => { dataFilter.processEvent(event); expect(event.context['userId']).toBe(uuidWithManyDigits); - expect(event.context['sessionId']).toBe(uuidUpperCase); + expect(event.context['requestId']).toBe(uuidUpperCase); expect(event.context['transactionId']).toBe(uuidNoDashes); expect(event.addons['vue']['props']['componentId']).toBe(uuidWithManyDigits); });