Skip to content

Commit 4f9d0e4

Browse files
committed
fix(sanitize.util.ts): add recursive sanitization for nested metadata
1 parent b4e47a6 commit 4f9d0e4

2 files changed

Lines changed: 70 additions & 6 deletions

File tree

packages/server/src/utils/sanitize.util.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,52 @@ describe('Sanitization Utilities', () => {
495495
const input = { userAgent: 'Moz\u0000illa/5.0' }
496496
expect(sanitizeAuditMetadata(input)).toEqual({ userAgent: 'Mozilla/5.0' })
497497
})
498+
499+
it('should recursively sanitize nested objects with sensitive keys', () => {
500+
const input = {
501+
configuration: {
502+
apiKey: 'secret-key-123',
503+
timeout: 30
504+
},
505+
settings: {
506+
password: 'mypassword'
507+
}
508+
}
509+
510+
expect(sanitizeAuditMetadata(input)).toEqual({
511+
configuration: {
512+
apiKey: '********',
513+
timeout: 30
514+
},
515+
settings: {
516+
password: '********'
517+
}
518+
})
519+
})
520+
521+
it('should sanitize arrays when key name is not sensitive', () => {
522+
const input = {
523+
items: [{ apiKey: 'secret1' }, { apiKey: 'secret2' }],
524+
ports: [8080, 3000]
525+
}
526+
527+
expect(sanitizeAuditMetadata(input)).toEqual({
528+
items: [{ apiKey: '********' }, { apiKey: '********' }],
529+
ports: [8080, 3000]
530+
})
531+
})
532+
533+
it('should redact entire value when key itself is sensitive, even if it is an array', () => {
534+
const input = {
535+
tokens: ['token1', 'token2'],
536+
passwords: ['pass1', 'pass2']
537+
}
538+
539+
expect(sanitizeAuditMetadata(input)).toEqual({
540+
tokens: '********',
541+
passwords: '********'
542+
})
543+
})
498544
})
499545

500546
describe('Integration scenarios', () => {

packages/server/src/utils/sanitize.util.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,32 @@ export function sanitizeAuditMetadata(metadata: Record<string, any> | undefined
144144
'cvv'
145145
]
146146

147-
const sanitized: Record<string, any> = { ...metadata }
148-
149-
for (const key of Object.keys(sanitized)) {
147+
function sanitizeValue(value: any, key: string): any {
150148
const lowerKey = key.toLowerCase()
151-
if (sensitiveFields.some((field) => lowerKey.includes(field))) {
152-
sanitized[key] = '********'
149+
const isSensitive = sensitiveFields.some((field) => lowerKey.includes(field))
150+
151+
if (isSensitive) {
152+
return '********'
153+
}
154+
155+
if (value && typeof value === 'object' && !Array.isArray(value)) {
156+
return sanitizeObject(value)
157+
}
158+
159+
if (Array.isArray(value)) {
160+
return value.map((item, index) => sanitizeValue(item, `${key}[${index}]`))
161+
}
162+
163+
return value
164+
}
165+
166+
function sanitizeObject(obj: Record<string, any>): Record<string, any> {
167+
const result: Record<string, any> = {}
168+
for (const key of Object.keys(obj)) {
169+
result[key] = sanitizeValue(obj[key], key)
153170
}
171+
return result
154172
}
155173

156-
return sanitizeNullBytes(sanitized)
174+
return sanitizeNullBytes(sanitizeObject(metadata))
157175
}

0 commit comments

Comments
 (0)