Skip to content

Commit 04d075f

Browse files
committed
code rabbit feedback
1 parent 2d0897c commit 04d075f

File tree

5 files changed

+298
-81
lines changed

5 files changed

+298
-81
lines changed

app/src/Sentry.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,73 @@ interface BaseContext {
2222
stage: string;
2323
}
2424

25+
// Security: Whitelist of allowed tag keys to prevent XSS
26+
const ALLOWED_TAG_KEYS = new Set([
27+
'session_id',
28+
'platform',
29+
'stage',
30+
'circuitType',
31+
'currentState',
32+
'scanType',
33+
'error_code',
34+
'proof_step',
35+
'scan_result',
36+
'verification_status',
37+
'document_type',
38+
]);
39+
40+
// Security: Sanitize tag values to prevent XSS
41+
const sanitizeTagValue = (value: unknown): string => {
42+
if (value == null) return '';
43+
44+
const stringValue = String(value);
45+
46+
// Truncate to safe length
47+
const MAX_TAG_LENGTH = 200;
48+
const truncated =
49+
stringValue.length > MAX_TAG_LENGTH
50+
? stringValue.substring(0, MAX_TAG_LENGTH) + '...'
51+
: stringValue;
52+
53+
// Escape HTML characters and remove potentially dangerous characters
54+
return (
55+
truncated
56+
.replace(/[<>&"']/g, char => {
57+
switch (char) {
58+
case '<':
59+
return '&lt;';
60+
case '>':
61+
return '&gt;';
62+
case '&':
63+
return '&amp;';
64+
case '"':
65+
return '&quot;';
66+
case "'":
67+
return '&#x27;';
68+
default:
69+
return char;
70+
}
71+
})
72+
// Remove control characters and non-printable characters
73+
.replace(/[^\x20-\x7E]/g, '')
74+
);
75+
};
76+
77+
// Security: Sanitize tag key to prevent XSS
78+
const sanitizeTagKey = (key: string): string | null => {
79+
// Only allow whitelisted keys
80+
if (!ALLOWED_TAG_KEYS.has(key)) {
81+
return null;
82+
}
83+
84+
// Additional validation: alphanumeric and underscores only
85+
if (!/^[a-zA-Z0-9_]+$/.test(key)) {
86+
return null;
87+
}
88+
89+
return key;
90+
};
91+
2592
export interface NFCScanContext extends BaseContext, Record<string, unknown> {
2693
scanType: 'mrz' | 'can';
2794
}
@@ -167,7 +234,11 @@ export const logEvent = (
167234
scope.setTag('platform', platform);
168235
scope.setTag('stage', stage);
169236
Object.entries(rest).forEach(([key, value]) => {
170-
scope.setTag(key, String(value));
237+
const sanitizedKey = sanitizeTagKey(key);
238+
if (sanitizedKey) {
239+
const sanitizedValue = sanitizeTagValue(value);
240+
scope.setTag(sanitizedKey, sanitizedValue);
241+
}
171242
});
172243
if (userId) {
173244
scope.setUser({ id: userId });

app/src/Sentry.web.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,73 @@ interface BaseContext {
2121
stage: string;
2222
}
2323

24+
// Security: Whitelist of allowed tag keys to prevent XSS
25+
const ALLOWED_TAG_KEYS = new Set([
26+
'session_id',
27+
'platform',
28+
'stage',
29+
'circuitType',
30+
'currentState',
31+
'scanType',
32+
'error_code',
33+
'proof_step',
34+
'scan_result',
35+
'verification_status',
36+
'document_type',
37+
]);
38+
39+
// Security: Sanitize tag values to prevent XSS
40+
const sanitizeTagValue = (value: unknown): string => {
41+
if (value == null) return '';
42+
43+
const stringValue = String(value);
44+
45+
// Truncate to safe length
46+
const MAX_TAG_LENGTH = 200;
47+
const truncated =
48+
stringValue.length > MAX_TAG_LENGTH
49+
? stringValue.substring(0, MAX_TAG_LENGTH) + '...'
50+
: stringValue;
51+
52+
// Escape HTML characters and remove potentially dangerous characters
53+
return (
54+
truncated
55+
.replace(/[<>&"']/g, char => {
56+
switch (char) {
57+
case '<':
58+
return '&lt;';
59+
case '>':
60+
return '&gt;';
61+
case '&':
62+
return '&amp;';
63+
case '"':
64+
return '&quot;';
65+
case "'":
66+
return '&#x27;';
67+
default:
68+
return char;
69+
}
70+
})
71+
// Remove control characters and non-printable characters
72+
.replace(/[^\x20-\x7E]/g, '')
73+
);
74+
};
75+
76+
// Security: Sanitize tag key to prevent XSS
77+
const sanitizeTagKey = (key: string): string | null => {
78+
// Only allow whitelisted keys
79+
if (!ALLOWED_TAG_KEYS.has(key)) {
80+
return null;
81+
}
82+
83+
// Additional validation: alphanumeric and underscores only
84+
if (!/^[a-zA-Z0-9_]+$/.test(key)) {
85+
return null;
86+
}
87+
88+
return key;
89+
};
90+
2491
export interface NFCScanContext extends BaseContext, Record<string, unknown> {
2592
scanType: 'mrz' | 'can';
2693
}
@@ -159,7 +226,11 @@ export const logEvent = (
159226
scope.setTag('platform', platform);
160227
scope.setTag('stage', stage);
161228
Object.entries(rest).forEach(([key, value]) => {
162-
scope.setTag(key, String(value));
229+
const sanitizedKey = sanitizeTagKey(key);
230+
if (sanitizedKey) {
231+
const sanitizedValue = sanitizeTagValue(value);
232+
scope.setTag(sanitizedKey, sanitizedValue);
233+
}
163234
});
164235
if (userId) {
165236
scope.setUser({ id: userId });

0 commit comments

Comments
 (0)