You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(desktop): SSRF hardening for the browser agent + review fixes
Shared SSRF primitive:
- Extract IP classification into @sim/security/ssrf (isPrivateIp,
isPrivateIpHost, isIpLiteral, unwrapIpv6Brackets). Collapses the two
divergent isPrivateOrReservedIP copies in apps/sim and the ad-hoc regex
copies in sap_concur/zoominfo/sap contracts into one audited, ipaddr.js-based
implementation consumed by both apps. All callers migrated; no logic left
behind.
Browser-agent SSRF guard (apps/desktop):
- The agent partition's onBeforeRequest is now the authoritative choke point:
document navigations (top-level + iframes) get a full DNS-resolving check —
covering page-initiated navigation the driver never sees (redirects, link
clicks, location.href, meta-refresh) — and subresources get a cheap
synchronous literal-IP backstop.
- browser_navigate / browser_open_tab validate up front so the model gets a
clean error instead of a silent load failure.
- Blocks loopback, RFC1918, link-local/cloud-metadata (169.254.169.254), and
obfuscated/IPv4-mapped forms; hostnames are resolved (DNS-rebinding aware).
Other hardening:
- crashReporter: local-only native minidumps (no backend, uploadToServer:false),
crash-dump dir recorded in the event log.
- CSP fallback: a minimal, non-drifting policy injected only when an app-origin
document response ships no CSP of its own.
- window.open (MCP OAuth) gated to https so a renderer-controlled frame name
can't ride an http URL into an in-app window.
- updater: shared configureAutoUpdater re-asserts channel/allowDowngrade on both
the launch and manual-check paths.
- handoff: the loopback listener now tears down only after the CSRF state
validates, not on any format-valid request (self-DoS guard).
- cdp: per-WebContents callbacks so a background tab's events reach its own
driver.
- config: drop the unreachable bare '::1' loopback entry.
- README: correct the App Sandbox / security-scoped-bookmark note for the
Developer ID build.
Tests: @sim/security/ssrf (67), desktop suite (200), affected apps/sim suites
green; type-check + biome clean across desktop, security, and touched sim files.
Copy file name to clipboardExpand all lines: apps/desktop/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -137,7 +137,7 @@ Good fits for the bridge: OS notifications + dock badge on workflow completion,
137
137
The main Copilot agent can inspect a user-selected local directory in the desktop app through request-local client tools (`local_mount_directory`, `local_list_mounts`, `local_list`, `local_glob`, `local_read`, `local_grep`, `local_stat`, and `local_forget_mount`). This capability is:
138
138
139
139
-**Explicit and read-only:** the native folder picker creates the grant; there are no write/delete/execute operations.
140
-
-**Remembered securely:** grants are encrypted in Electron's private app data with OS-backed `safeStorage` and restored with the same opaque URI after a normal app restart. Sandboxed macOS builds also retain the security-scoped bookmark. There is no plaintext fallback: when secure storage is unavailable, the returned mount has `remembered: false` and lasts only for that app session.
140
+
-**Remembered securely:** grants are encrypted in Electron's private app data with OS-backed `safeStorage` and restored with the same opaque URI after a normal app restart. (A security-scoped bookmark is stored alongside each grant, but it is a no-op in the current Developer ID build — only the macOS App Sandbox consumes it — and is kept purely for forward-compatibility should a sandboxed/MAS build ever ship.) There is no plaintext fallback: when secure storage is unavailable, the returned mount has `remembered: false` and lasts only for that app session.
141
141
-**Revocable:**`local_forget_mount` removes one grant. All grants are removed on explicit sign-out or server-origin change so another Sim account or server cannot inherit them. Normal app quit only releases active OS handles and keeps the encrypted grants.
142
142
-**Opaque:** renderer and model see only `localfs://<mount-id>/...` URIs. Electron resolves every URI, checks lexical and realpath containment, and refuses symlink escapes.
143
143
-**Desktop-only:** the web app advertises these request-local tools only when `window.simDesktop.localFilesystem` is present. They are available directly to the main agent and are not added to subagent allowlists.
0 commit comments