Skip to content

fix: XSS validation filters shielding dynamic node identifier strings (#9) - #37

Merged
JamesEjembi merged 8 commits into
Lumina-etwork:mainfrom
jobbykings:fix/issue-9-xss-sanitization-filters
Jun 20, 2026
Merged

fix: XSS validation filters shielding dynamic node identifier strings (#9)#37
JamesEjembi merged 8 commits into
Lumina-etwork:mainfrom
jobbykings:fix/issue-9-xss-sanitization-filters

Conversation

@jobbykings

Copy link
Copy Markdown
Contributor

Summary

Implements XSS validation filters that shield dynamic node identifier strings rendered from on-chain Soroban contract data.

Changes

  • Install isomorphic-dompurify for SSR-compatible DOMPurify sanitization
  • Create src/utils/sanitizer.ts with sanitizeNodeString (b/i/a allowlist) and detectDangerPatterns monitoring layer
  • Build NodeCard and NodeList components with sanitized rendering of all 7 metadata fields
  • Add NodeConfigSummary to QRProvisionPanel with sanitized config display
  • Add Content-Security-Policy headers in next.config.ts as defence-in-depth
  • Add Playwright E2E tests covering script tags, event handlers, JS URIs, encoded entities, and homoglyph attacks
  • Create /node-list-demo page wiring NodeCard/NodeList for manual testing

Validation

  • TypeScript: 0 errors
  • Lint: 0 errors/warnings on changed files
  • All changed strings pass through DOMPurify before rendering

Closes #9

…Lumina-etwork#9)

- Add isomorphic-dompurify for SSR-compatible DOMPurify sanitization
- Create src/utils/sanitizer.ts with sanitizeNodeString (b/i/a allowlist)
  and detectDangerPatterns monitoring layer
- Build NodeCard and NodeList components with sanitized on-chain data
  rendering for labels, descriptions, location, owner, firmware, etc.
- Add NodeConfigSummary to QRProvisionPanel with sanitized config display
- Add Content-Security-Policy headers to next.config.ts as defence-in-depth
- Add Playwright E2E tests covering script tags, event handlers, JS URIs,
  encoded entities, and Unicode homoglyph attacks
- Create /node-list-demo page wiring NodeCard/NodeList for manual testing

Closes Lumina-etwork#9
… Node.js

The DOMPurify afterSanitizeAttributes hook used instanceof HTMLAnchorElement
which is undefined in Node.js/SSR environments. Replaced with nodeName string
comparison ('A') as primary check, falling back to instanceof when the
browser DOM constructor is available.
…ML stripping

- Fix test cleanup: removeChild was called on already-removed container
  after loop, causing NotFoundError in CI
- Fix NodeCard aria-label: use regex to strip HTML tags from label so
  aria-label contains plain text only (e.g. 'SFO Edge Router' not
  '<b>SFO</b> Edge Router')
- Expose sanitizeNodeString on window.__sanitizeNodeString__ in
  /node-list-demo page for E2E test access (cast window properly)
- Rewrite all QR-based tests to use page.evaluate calling
  window.__sanitizeNodeString__ directly — no wallet mocking needed
- Use actual Unicode fullwidth homoglyph characters (U+FF1C/U+FF1E)
  in homoglyph test payload instead of ASCII angle brackets
…aluate

waitForSelector was not sufficient — useEffect that exposes
window.__sanitizeNodeString__ runs after DOM attach. Added
waitForFunction guard so tests don't race with the effect.
Also simplified test helpers: gotoDemoAndWait + sanitize.
@JamesEjembi

Copy link
Copy Markdown
Contributor

CI failed

- Switch CI workflow back from npm install to npm ci (standard CI practice)
- Remove duplicate tailwindcss entry in devDependencies (merge artifact)
- Regenerate package-lock.json cleanly after merge with main

npm ci requires an exact lock file match; the previous npm install
change was masking an inconsistent lock file from the main merge.
With a clean regenerated lock file, npm ci is both faster and more
deterministic.
- next.config.ts: allow 'unsafe-eval' in script-src CSP only in dev mode.
  Next.js webpack HMR requires eval() for hot module replacement;
  without it the dev server can silently break in CI environments.

- WalletProvider.tsx: fix setGeneration called inside setPublicKey's
  functional updater. React 18+ silently discards state setters called
  inside another state updater (impure render). Replaced with a
  prevPublicKeyRef comparison before calling setGeneration directly.

@JamesEjembi JamesEjembi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JamesEjembi
JamesEjembi merged commit 021fd60 into Lumina-etwork:main Jun 20, 2026
1 check passed
Timrossid added a commit to Timrossid/Lumina-Frontend that referenced this pull request Jun 29, 2026
The lockfile produced by the previous git merge of PR Lumina-etwork#37 had
corrupted entries - @jest/console and @jest/diff-sequences were
incorrectly marked as optional with platform-specific os constraints,
causing npm ci to fail on CI runners.

Reconstructed from the two parent lockfiles (0c36d0d and 021fd60)
using a clean union merge, then verified with npm install
--package-lock-only. All 876 node_modules entries are present and
cross-platform compatible.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XSS Validation Filters Shielding Dynamic Node Identifier Strings

2 participants