Skip to content

Harden layout persistence against poisoned localStorage - #869

Draft
bingenito wants to merge 1 commit into
morganstanley:mainfrom
bingenito:security/core-layout-storage-hardening
Draft

Harden layout persistence against poisoned localStorage#869
bingenito wants to merge 1 commit into
morganstanley:mainfrom
bingenito:security/core-layout-storage-hardening

Conversation

@bingenito

@bingenito bingenito commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

loadLayout replays a layout JSON blob from localStorage on every future session, so a one-shot XSS that plants a malicious desktopJS-layouts entry keeps firing on reload. This closes that off in ContainerBase:

…F#16)

loadLayout replays a layout JSON blob from localStorage on every future
session, so a one-shot XSS that plants a malicious desktopJS-layouts
entry keeps firing on reload. Close that off:

- sanitizeUrl rejects non-http(s)/relative schemes (javascript:, data:,
  etc.) on persisted window urls before createWindow is called (F#14).
- Layout JSON is parsed with a reviver that strips __proto__/constructor/
  prototype keys, closing the Object.assign(window.options, ...)
  prototype-pollution gadget, and malformed/missing storage no longer
  throws out of getLayoutFromStorage/getLayouts (F#13).
- ContainerBase.storage is now set via an overridable constructor
  parameter instead of being hard-bound to window.localStorage (F#16).

F#03 (Object.assign smuggling arbitrary createWindow option keys) is
intentionally not addressed here: createWindow is a thin pass-through
shim in both remaining containers (window.open features string /
fin.desktop.Window options), so smuggled keys carry no more privilege
than a caller already has by calling createWindow/window.open directly.
The one option key that did escalate privilege, Electron's
webPreferences, is removed along with the rest of the Electron package.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.36%. Comparing base (133c5f1) to head (d4ef278).

Files with missing lines Patch % Lines
packages/desktopjs/src/container.ts 96.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #869      +/-   ##
==========================================
+ Coverage   74.03%   74.36%   +0.32%     
==========================================
  Files          16       16              
  Lines        1510     1529      +19     
  Branches      318      324       +6     
==========================================
+ Hits         1118     1137      +19     
+ Misses        392      386       -6     
- Partials        0        6       +6     
Flag Coverage Δ
unittests 74.36% <96.66%> (+0.32%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/desktopjs/src/container.ts 93.08% <96.66%> (+0.93%) ⬆️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bingenito bingenito changed the title Harden layout persistence against poisoned localStorage (F#13, F#14, F#16) Harden layout persistence against poisoned localStorage Jul 31, 2026
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.

1 participant