bug(security): Preset manager interpolates name/description into innerHTML #114

Closed
opened 2026-08-26 15:11:13 +01:00 by gronod · 1 comment
Owner
Field Value
Labels Kind/Security, Priority/Medium
Priority Medium
Milestone v0.3.3 hotfix
Related #88
Branch fix/presets-dpi-xss (from development)
Pair with 05-preset-dpi.md — same PR

Description

renderManagePresetsList in src/js/presets.js builds DOM with string-interpolated innerHTML. Custom and imported presets (import_preset_jsonsave_preset) are attacker-controlled JSON. A description of <img src=x onerror=alert(1)> executes in the Tauri WebView, which is a privileged surface.

Current behaviour

item.innerHTML = `
  <div>
    <div>${p.name} …</div>
    <div>${p.description || "No description"}</div>
  </div>
`;

p.name and p.description are not escaped. Import does not reject HTML or control characters.

Proposed solution

  • Build the row with createElement and textContent for name, description, and the meta line.
  • Keep Export / Delete as created elements with data-id (already used).
  • Optionally sanitise on import in Rust: reject name / description containing < or control chars; max length 200 / 500.
  • Do not add a general HTML sanitiser. textContent is enough.

Files

  • src/js/presets.jsrenderManagePresetsList
  • src-tauri/src/settings.rsimport_preset_json validation

Acceptance criteria

  • Importing a preset whose name is <img src=x onerror=alert(1)> shows the literal text, does not fire error handlers, and does not inject nodes.
  • The same is true for description.
  • Built-in presets still render the Built-in badge and Export / Delete correctly.
  • Delete and Export buttons still work after the DOM change.

Dependencies

None. Implement with issue 05 in the same PR.

| Field | Value | |---|---| | Labels | `Kind/Security`, `Priority/Medium` | | Priority | Medium | | Milestone | v0.3.3 hotfix | | Related | #88 | | Branch | `fix/presets-dpi-xss` (from `development`) | | Pair with | [05-preset-dpi.md](05-preset-dpi.md) — same PR | ## Description `renderManagePresetsList` in `src/js/presets.js` builds DOM with string-interpolated `innerHTML`. Custom and **imported** presets (`import_preset_json` → `save_preset`) are attacker-controlled JSON. A description of `<img src=x onerror=alert(1)>` executes in the Tauri WebView, which is a privileged surface. ## Current behaviour ```javascript item.innerHTML = ` <div> <div>${p.name} …</div> <div>${p.description || "No description"}</div> … </div> `; ``` `p.name` and `p.description` are not escaped. Import does not reject HTML or control characters. ## Proposed solution - Build the row with `createElement` and `textContent` for name, description, and the meta line. - Keep Export / Delete as created elements with `data-id` (already used). - Optionally sanitise on import in Rust: reject `name` / `description` containing `<` or control chars; max length 200 / 500. - Do not add a general HTML sanitiser. `textContent` is enough. ## Files - `src/js/presets.js` — `renderManagePresetsList` - `src-tauri/src/settings.rs` — `import_preset_json` validation ## Acceptance criteria - [ ] Importing a preset whose `name` is `<img src=x onerror=alert(1)>` shows the literal text, does not fire `error` handlers, and does not inject nodes. - [ ] The same is true for `description`. - [ ] Built-in presets still render the **Built-in** badge and Export / Delete correctly. - [ ] Delete and Export buttons still work after the DOM change. ## Dependencies None. Implement with issue 05 in the same PR.
gronod added this to the v0.3.3 Hot fixes milestone 2026-08-26 15:11:13 +01:00
gronod added the Kind/Bug
Reviewed
Confirmed
1
Priority
Medium
3
labels 2026-08-26 15:11:13 +01:00
gronod added Kind/Security and removed Kind/Bug labels 2026-08-26 15:13:25 +01:00
gronod changed title from # bug(security): Preset manager interpolates name/description into innerHTML to bug(security): Preset manager interpolates name/description into innerHTML 2026-08-27 15:31:12 +01:00
Author
Owner

Resolved via PR #122. renderManagePresetsList now safely builds DOM elements via createElement and textContent. Added string length / DPI validation in import_preset_json.

Resolved via PR #122. `renderManagePresetsList` now safely builds DOM elements via `createElement` and `textContent`. Added string length / DPI validation in `import_preset_json`.
Sign in to join this conversation.