Skip to content

Commit c4cc417

Browse files
authored
fix(grouper): filter oldPassword and newPassword in event payload (#516)
* fix(grouper): filter oldPassword and newPassword in event payload * chore: add more keys and update tests * chore: lint fix * fix(tests): rename sessionId to requestId in data-filter tests for clarity
1 parent 4189b0a commit c4cc417

2 files changed

Lines changed: 132 additions & 11 deletions

File tree

workers/grouper/src/data-filter.ts

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,71 @@ export default class DataFilter {
3636
private filteredValuePlaceholder = '[filtered]';
3737

3838
/**
39-
* Possibly sensitive keys
39+
* Possibly sensitive keys (lowercase; keys are compared via key.toLowerCase())
4040
*/
4141
private possiblySensitiveDataKeys = new Set([
42-
'pan',
43-
'secret',
44-
'credentials',
45-
'card[number]',
46-
'password',
42+
/**
43+
* Authorization and sessions
44+
*/
4745
'auth',
46+
'authorization',
4847
'access_token',
4948
'accesstoken',
49+
'token',
50+
'jwt',
51+
'session',
52+
'sessionid',
53+
'session_id',
54+
/**
55+
* API keys and secure tokens
56+
*/
57+
'api_key',
58+
'apikey',
59+
'x-api-key',
60+
'x-auth-token',
61+
'bearer',
62+
'client_secret',
63+
'secret',
64+
'credentials',
65+
/**
66+
* Passwords
67+
*/
68+
'password',
69+
'passwd',
70+
'mysql_pwd',
71+
'oldpassword',
72+
'old-password',
73+
'old_password',
74+
'newpassword',
75+
'new-password',
76+
'new_password',
77+
/**
78+
* Encryption keys
79+
*/
80+
'private_key',
81+
'ssh_key',
82+
/**
83+
* Payments data
84+
*/
85+
'card',
86+
'cardnumber',
87+
'card[number]',
88+
'creditcard',
89+
'credit_card',
90+
'pan',
91+
'pin',
92+
'security_code',
93+
'stripetoken',
94+
'cloudpayments_public_id',
95+
'cloudpayments_secret',
96+
/**
97+
* Config and connections
98+
*/
99+
'dsn',
100+
/**
101+
* Personal data
102+
*/
103+
'ssn',
50104
]);
51105

52106
/**
@@ -127,7 +181,9 @@ export default class DataFilter {
127181
*/
128182
const clean = value.replace(/\D/g, '');
129183

130-
// Reset last index to 0
184+
/**
185+
* Reset last index to 0
186+
*/
131187
this.bankCardRegex.lastIndex = 0;
132188
if (!this.bankCardRegex.test(clean)) {
133189
return value;

workers/grouper/tests/data-filter.test.ts

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,57 @@ function generateEvent({ context, addons }: {context?: Json, addons?: EventAddon
2828
}
2929

3030
/**
31-
* Example of object with sensitive information
31+
* Example of object with sensitive information.
32+
* Keys intentionally use snake_case/kebab-case to match data-filter list.
3233
*/
34+
/* eslint-disable @typescript-eslint/naming-convention */
3335
const sensitiveDataMock = {
3436
pan: '5500 0000 0000 0004',
3537
secret: 'D6A03F5C2E0E356F262D56F44370E1CD813583B2',
3638
credentials: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67',
3739
'card[number]': '5500 0000 0000 0004',
3840
password: 'bFb7PBm6nZ7RJRq9',
41+
oldpassword: 'oldSecret123',
42+
newpassword: 'newSecret456',
43+
'old-password': 'oldSecretHyphen',
44+
old_password: 'oldSecretUnderscore',
45+
'new-password': 'newSecretHyphen',
46+
new_password: 'newSecretUnderscore',
3947
auth: 'C4CA4238A0B923820DCC509A6F75849B',
40-
// eslint-disable-next-line @typescript-eslint/naming-convention
4148
access_token: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67',
4249
accessToken: '70BA33708CBFB103F1A8E34AFEF333BA7DC021022B2D9AAA583AABB8058D8D67',
4350
};
4451

52+
/**
53+
* Additional sensitive keys (newly added / previously uncovered).
54+
* Keys intentionally use snake_case to match data-filter list.
55+
*/
56+
const additionalSensitiveDataMock = {
57+
authorization: 'Bearer abc123',
58+
token: 'token-value',
59+
jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
60+
session: 'sess_xyz',
61+
session_id: 'sid_789',
62+
api_key: 'sk_live_xxx',
63+
bearer: 'Bearer token',
64+
client_secret: 'client_secret_value',
65+
passwd: 'passwd_value',
66+
mysql_pwd: 'mysql_pwd_value',
67+
private_key: '-----BEGIN PRIVATE KEY-----',
68+
ssh_key: 'ssh-rsa AAAA...',
69+
card: '4111111111111111',
70+
cardnumber: '5500000000000004',
71+
creditcard: '4111111111111111',
72+
pin: '1234',
73+
security_code: '999',
74+
stripetoken: 'tok_xxx',
75+
cloudpayments_public_id: 'pk_xxx',
76+
cloudpayments_secret: 'secret_xxx',
77+
dsn: 'postgres://user:pass@host/db',
78+
ssn: '123-45-6789',
79+
};
80+
/* eslint-enable @typescript-eslint/naming-convention */
81+
4582
describe('GrouperWorker', () => {
4683
const dataFilter = new DataFilter();
4784

@@ -123,6 +160,34 @@ describe('GrouperWorker', () => {
123160
});
124161
});
125162

163+
test('should filter additional sensitive keys (authorization, token, payment, dsn, ssn, etc.) in context', async () => {
164+
const event = generateEvent({
165+
context: additionalSensitiveDataMock,
166+
});
167+
168+
dataFilter.processEvent(event);
169+
170+
Object.keys(additionalSensitiveDataMock).forEach((key) => {
171+
expect(event.context[key]).toBe('[filtered]');
172+
});
173+
});
174+
175+
test('should filter additional sensitive keys in addons', async () => {
176+
const event = generateEvent({
177+
addons: {
178+
vue: {
179+
props: additionalSensitiveDataMock,
180+
},
181+
},
182+
});
183+
184+
dataFilter.processEvent(event);
185+
186+
Object.keys(additionalSensitiveDataMock).forEach((key) => {
187+
expect(event.addons['vue']['props'][key]).toBe('[filtered]');
188+
});
189+
});
190+
126191
test('should not replace values with keynames not in a list', async () => {
127192
const normalValue = 'test123';
128193
const event = generateEvent({
@@ -154,7 +219,7 @@ describe('GrouperWorker', () => {
154219
const event = generateEvent({
155220
context: {
156221
userId: uuidWithManyDigits,
157-
sessionId: uuidUpperCase,
222+
requestId: uuidUpperCase,
158223
transactionId: uuidNoDashes,
159224
},
160225
addons: {
@@ -169,7 +234,7 @@ describe('GrouperWorker', () => {
169234
dataFilter.processEvent(event);
170235

171236
expect(event.context['userId']).toBe(uuidWithManyDigits);
172-
expect(event.context['sessionId']).toBe(uuidUpperCase);
237+
expect(event.context['requestId']).toBe(uuidUpperCase);
173238
expect(event.context['transactionId']).toBe(uuidNoDashes);
174239
expect(event.addons['vue']['props']['componentId']).toBe(uuidWithManyDigits);
175240
});

0 commit comments

Comments
 (0)