Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@
**Vulnerability:** Several `escapeHtml` implementations used DOM manipulation (`document.createElement('div').innerHTML`) or incomplete string replacement, failing to escape single and double quotes.
**Learning:** Incomplete escaping allows XSS payloads to break out of HTML attributes (e.g., `<input value="${escapeHtml(userInput)}">`).
**Prevention:** Always use `String(text)` cast combined with a comprehensive replace chain for `&`, `<`, `>`, `"`, and `'` (e.g., `&#039;`) in custom string escaping functions.

## 2025-06-26 - [Title] Fix attribute-based XSS by strictly escaping single quotes in custom HTML escape functions
**Vulnerability:** Custom HTML escaping functions across the codebase (`escHtml` in `site/layers.js` and others) failed to cast input strings correctly and missed escaping single quotes (`'`). This left attributes vulnerable to XSS attacks (e.g. `data-node-id` getting a payload that breaks out using single quotes).
**Learning:** Even simple string replacement functions designed for HTML escaping need to explicitly handle single quotes and securely cast inputs, as relying on missing character replacements creates XSS vectors within HTML attributes.
**Prevention:** Always use `String(text)` in escape functions before replacing characters. Ensure that both double (`"`) and single quotes (`'`) are escaped; specifically, use `&#039;` for single quotes to ensure maximum browser compatibility.
2 changes: 1 addition & 1 deletion site/layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function initLayersPanel(api) {
path: 'γ€œ', text: 'T', style: 'β—†', edge: '⟢', note: 'β—‡', spec: 'β—‡'
};

function escHtml(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
function escHtml(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#039;'); }

/** Parse FD source into a hierarchical layer tree. */
function parseLayerTree(source) {
Expand Down
Loading