feat(#285): Add input sanitization for XSS prevention

Security improvements:
- Create sanitization utility using sanitize-html library
- Add @Sanitize() and @SanitizeObject() decorators for DTOs
- Apply sanitization to vulnerable fields:
  - Connection rejection/disconnection reasons
  - Connection metadata
  - Identity linking metadata
  - Command payloads
- Remove script tags, event handlers, javascript: URLs
- Prevent data exfiltration, CSS-based XSS, SVG-based XSS

Changes:
- Add sanitize.util.ts with recursive sanitization functions
- Add sanitize.decorator.ts for class-transformer integration
- Update connection.dto.ts with sanitization decorators
- Update identity-linking.dto.ts with sanitization decorators
- Update command.dto.ts with sanitization decorators
- Add comprehensive test coverage including attack vectors

Part of M7.1 Remediation Sprint P1 security fixes.

Fixes #285

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 21:47:32 -06:00
parent 3bba2f1c33
commit 01639fff95
24 changed files with 921 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
/**
* Sanitize Decorator
*
* Custom class-validator decorator to sanitize string input and prevent XSS.
*/
import { Transform } from "class-transformer";
import { sanitizeString, sanitizeObject } from "../utils/sanitize.util";
/**
* Sanitize decorator for DTO properties
* Automatically sanitizes string values to prevent XSS attacks
*
* Usage:
* ```typescript
* class MyDto {
* @Sanitize()
* @IsString()
* userInput!: string;
* }
* ```
*/
export function Sanitize(): PropertyDecorator {
return Transform(({ value }: { value: unknown }) => {
if (typeof value === "string") {
return sanitizeString(value);
}
return value;
});
}
/**
* SanitizeObject decorator for nested objects
* Recursively sanitizes all string values in an object
*
* Usage:
* ```typescript
* class MyDto {
* @SanitizeObject()
* @IsObject()
* metadata?: Record<string, unknown>;
* }
* ```
*/
export function SanitizeObject(): PropertyDecorator {
return Transform(({ value }: { value: unknown }) => {
if (typeof value === "object" && value !== null) {
return sanitizeObject(value as Record<string, unknown>);
}
return value;
});
}