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.
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
changed title from # bug(security): Preset manager interpolates name/description into innerHTML to bug(security): Preset manager interpolates name/description into innerHTML2026-08-27 15:31:12 +01:00
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`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Kind/Security,Priority/Mediumfix/presets-dpi-xss(fromdevelopment)Description
renderManagePresetsListinsrc/js/presets.jsbuilds DOM with string-interpolatedinnerHTML. 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
p.nameandp.descriptionare not escaped. Import does not reject HTML or control characters.Proposed solution
createElementandtextContentfor name, description, and the meta line.data-id(already used).name/descriptioncontaining<or control chars; max length 200 / 500.textContentis enough.Files
src/js/presets.js—renderManagePresetsListsrc-tauri/src/settings.rs—import_preset_jsonvalidationAcceptance criteria
nameis<img src=x onerror=alert(1)>shows the literal text, does not fireerrorhandlers, and does not inject nodes.description.Dependencies
None. Implement with issue 05 in the same PR.
# bug(security): Preset manager interpolates name/description into innerHTMLto bug(security): Preset manager interpolates name/description into innerHTMLResolved via PR #122.
renderManagePresetsListnow safely builds DOM elements viacreateElementandtextContent. Added string length / DPI validation inimport_preset_json.