-
Notifications
You must be signed in to change notification settings - Fork 13
Closed
Description
Severity: Low
File: src/web/public/app.js:9311
Description
Case names returned from /api/cases are inserted into <option> elements without HTML escaping:
cases.forEach(c => {
const displayName = c.name.length > maxNameLength
? c.name.substring(0, maxNameLength) + '…'
: c.name;
options += `<option value="${c.name}">${displayName}</option>`;
// ^^^^^^^ ^^^^^^^^^^^
// both missing escapeHtml()
});escapeHtml() exists in the codebase and is used correctly elsewhere. Case names come from directory entries in ~/codeman-cases/ and from keys in ~/.codeman/linked-cases.json.
Note: The existing CSP includes 'unsafe-inline' in script-src, so CSP does not block inline script execution.
Proof of Concept
Linux (where <> are valid in directory names):
mkdir ~/codeman-cases/'"><img src=x onerror=alert(document.cookie)>'Cross-platform (via ~/.codeman/linked-cases.json):
{
"<img src=x onerror=alert(document.cookie)>": "/tmp/legit-path"
}Reload the Codeman UI — XSS fires when the quick-start dropdown renders.
Remediation
Apply escapeHtml() to both interpolation points:
options += `<option value="${this.escapeHtml(c.name)}">${this.escapeHtml(displayName)}</option>`;Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels