Skip to content

Sandbox renderers and encrypt dictation history - #4

Merged
gotzastory merged 4 commits into
mainfrom
cursor/sandbox-history-privacy-b956
Nov 9, 2026
Merged

gotzastory merged 4 commits into
mainfrom
cursor/sandbox-history-privacy-b956

Conversation

@gotzastory

Copy link
Copy Markdown
Owner

Summary

Hardens the two renderer windows and stops storing dictation history as plaintext.

  • The preload build is CommonJS dist-electron/preload.cjs (format: 'cjs'). Both windows set sandbox: true explicitly, with contextIsolation: true and nodeIntegration: false. Sandbox is not turned off.
  • will-navigate allows only the app page from pathToFileURL(...) (hash is allowed, a query string is not) and, in dev, the dev-server origin. Other file URLs and other origins are blocked. Dashboard loads use that same file URL.
  • The default session allows the media permission only for the widget and denies every other permission, including media for the dashboard. The Settings microphone list may therefore show generic labels until a Windows check confirms how enumerateDevices behaves without a dashboard grant.
  • history.json is no longer plaintext. The body is safeStorage ciphertext with a small magic header. A legacy {entries} file is migrated when encryption is available and left byte-for-byte alone when it is not. If encryption is unavailable, new entries are not written and the user gets one warning: ระบบเข้ารหัสประวัติยังไม่พร้อม จึงไม่บันทึกประวัติลงดิสก์. Ciphertext that cannot be decrypted is not overwritten; Clear history deletes that file. The 500-entry and 4 MB caps still apply to the plaintext payload.
  • Settings has บันทึกประวัติการถอดเสียง (saveHistory, default on). History already had ล้างประวัติ. Home and History copy now say the text is encrypted on this PC.

This branch does not change package-lock.json. It does edit electron/main.ts and electron/main.test.ts, which the app-fix PR also edits. Rebase this branch onto main after that PR merges.

Clipboard restore

Images are already restored. pasteAtCursor snapshots text/plain, text/html, text/rtf, and any image/* via clipboard.readImage(), then clipboard.write() puts them back together. Existing tests cover that path. No image-loss path showed up.

File drops are not restored, on purpose. CF_HDROP is standard clipboard format 15 and has no registered name. clipboard.readBuffer('CF_HDROP') calls RegisterClipboardFormat("CF_HDROP"), which is a different format, so it does not read the file list. FileNameW is one UTF-16 path, not the multi-file drop Explorer pastes, and writeBuffer cannot put bytes back onto format 15. Writing either buffer would look like a restore while the real drop is gone. The native host still sets the file flag, and paste refuses to touch the clipboard. electron/pasteText.test.ts asserts a file drop never calls writeText, write, or writeBuffer.

Tests

npm test (165) and npm run build passed. The production build emits dist-electron/preload.cjs as require("electron") / contextBridge, and the main bundle sets sandbox: !0 with nodeIntegration: !1.

Manual Windows check

This needs a packaged build, not just the unit tests:

  • window.typeless exists in both windows with sandbox on (dictation and the dashboard still load).
  • Hotkey, then paste into Chrome, Edge, and Notepad.
  • Switch windows during speech-to-text, then dictate again.
  • Copy an image, dictate, and confirm the image comes back after the restore delay.
  • Copy files in Explorer, dictate, and confirm the file drop is still on the clipboard (it must not be replaced).
  • Turn history off, dictate, and confirm nothing new is stored. Turn it on, dictate, and confirm History shows the text. Clear history. Inspect %APPDATA%/OpenPood/history.json and confirm the transcript is not readable as plaintext.
  • With encryption unavailable (if you can reproduce that), confirm the warning appears and a new transcript is not written into the file.
  • Settings microphone names may be blank because only the widget may use media. Confirm whether the chosen device still records.
Open in Web Open in Cursor 

cursoragent and others added 4 commits November 9, 2026 08:36
The preload is CommonJS so sandbox stays on. History is encrypted with safeStorage, can be turned off, and file drops are still left untouched because Electron cannot round-trip CF_HDROP.

Co-authored-by: Thana <gotzastory@users.noreply.github.com>
…y-privacy-b956

Co-authored-by: Thana <gotzastory@users.noreply.github.com>
…y-privacy-b956

Co-authored-by: Thana <gotzastory@users.noreply.github.com>

# Conflicts:
#	electron/main.test.ts
Co-authored-by: Thana <gotzastory@users.noreply.github.com>
@gotzastory
gotzastory merged commit 6190445 into main Nov 9, 2026
1 check passed
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.

2 participants