Problem Statement
The NodeCard component renders user-configured node labels, network names, and description fields that are stored on-chain and retrieved via Soroban contract queries. Because these values are set by network participants, they can contain arbitrary Unicode strings including HTML tags, JavaScript event handlers, and script payloads. The current implementation renders these strings via dangerouslySetInnerHTML or directly interpolates them into JSX without sanitization, creating a critical cross-site scripting (XSS) vector. An attacker can craft a node label that executes arbitrary JavaScript in the dashboard of every operator viewing that node.
Technical Bounds & Invariants
- Sanitization must occur at the rendering boundary, not at the storage layer (chain data is immutable).
- Only allowlisted HTML tags (b, i, a with rel=nofollow) may survive sanitization; all others must be stripped.
- All ampersand, angle bracket, quote, and apostrophe characters must be encoded in non-allowlisted contexts.
- The sanitizer must handle Unicode normalization attacks (e.g., homoglyph characters).
- Sanitization must complete within 5ms for strings up to 10KB to avoid render jank.
- The solution must use an existing battle-tested library (DOMPurify) and not a custom regex-based approach.
Codebase Navigation Guide
/src/components/network/NodeCard.tsx - Component rendering node labels and descriptions.
/src/utils/sanitizer.ts - (To be created) Centralized sanitization utility.
/src/components/network/NodeList.tsx - Renders multiple NodeCards in a list.
/src/types/network.ts - NodeData type with string fields that need sanitization.
Step-by-Step Resolution Blueprint
- Install DOMPurify (or its isomorphic variant isomorphic-dompurify for SSR compatibility).
- Create a sanitizer.ts module that exports a sanitizeNodeString function wrapping DOMPurify.sanitize with a restrictive allowlist configuration.
- Apply sanitizeNodeString to every text field in NodeCard before rendering, including: label, description, location, ownerName, firmwareVersion.
- Add a secondary layer of defense by setting Content-Security-Policy headers in the Next.js middleware config to block inline script execution.
- Write a regex-based "danger pattern" detector that logs console warnings when potentially malicious strings are detected (for monitoring/analytics).
- Add automated Playwright tests that attempt XSS injection via the onboarding flow and verify sanitized output.
- Audit the entire codebase for any other dangerouslySetInnerHTML usage and refactor to use the new sanitizer.
Problem Statement
The NodeCard component renders user-configured node labels, network names, and description fields that are stored on-chain and retrieved via Soroban contract queries. Because these values are set by network participants, they can contain arbitrary Unicode strings including HTML tags, JavaScript event handlers, and script payloads. The current implementation renders these strings via dangerouslySetInnerHTML or directly interpolates them into JSX without sanitization, creating a critical cross-site scripting (XSS) vector. An attacker can craft a node label that executes arbitrary JavaScript in the dashboard of every operator viewing that node.
Technical Bounds & Invariants
Codebase Navigation Guide
/src/components/network/NodeCard.tsx- Component rendering node labels and descriptions./src/utils/sanitizer.ts- (To be created) Centralized sanitization utility./src/components/network/NodeList.tsx- Renders multiple NodeCards in a list./src/types/network.ts- NodeData type with string fields that need sanitization.Step-by-Step Resolution Blueprint