Commit cb69d7a
authored
feat(desktop): SSRF hardening for the browser agent + review fixes (#5763)
* 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.
* fix(desktop): address review findings (handoff callback gate, fail-closed guards)
- handoff: gate onCallback on a non-consuming state match so a format-valid but
wrong/expired state no longer fires the callback (which surfaced a spurious
"sign-in failed" UI while the genuine callback was still pending). The
one-shot listener still survives wrong-state requests (self-DoS guard);
consume() re-validates and tears it down on the real callback.
- session: the agent-partition onBeforeRequest SSRF check now fails closed —
an unexpected rejection cancels the request instead of leaving it suspended.
- updater: the manual checkForUpdates() now has a .catch() that logs and shows
an error dialog instead of silently swallowing network/manifest failures.
* refactor: desktop cleanup, shared loopback helpers, api-validation reconcile
Desktop reuse / dead-code (whole-app audit):
- driver.ts: use shared `sleep` (@sim/utils/helpers) and `getErrorMessage`
(@sim/utils/errors) instead of local reimplementations; drop 7 banner
separators.
- Remove dead code: LocalFilesystemService.clear(), launcher isVisible(),
the unused `url` arg on onDownloadBlocked, and decideStartRoute's always-
'unknown' sessionState param + its dead branch (no launch-time probe by
design — see README).
- Extract the duplicated launcher load-failure tail into failLaunchLoad().
- handoff.ts: promote a loose comment to TSDoc.
Shared loopback helpers (@sim/security/ssrf):
- Add isLoopbackIp (full 127/8 + ::1 range) and isLoopbackHostname /
LOOPBACK_HOSTNAMES (exact-set), consolidating three duplicated copies:
mcp/domain-check.ts (now uses isLoopbackIp + isIpLiteral + unwrapIpv6Brackets,
drops its ipaddr import), connectors/s3.ts, and desktop config.ts /
navigation.ts (drop the local LOCAL_HOSTNAMES set). urls.ts keeps its own
client-side set to avoid pulling ipaddr.js into client bundles.
api-validation:strict reconcile (pre-existing dev drift, not from these changes):
- Allowlist speech/tts (raw-read streaming route that validates inline) in
INDIRECT_ZOD_ROUTES; annotate the launcher's validated-envelope double-cast.
Bump the route-count baseline 964→966 for dev's two already-merged speech
routes. Non-Zod and double-cast ratchets stay at baseline.
* fix(desktop): fail closed on DNS resolution failure in the agent SSRF guard
checkAgentUrl now blocks when dns.lookup throws instead of allowing the load.
Chromium resolves DNS independently of our Node lookup, so a host our resolver
can't resolve could still reach a private address via Chromium's resolver —
allowing it was a fail-open gap. Matches validateUrlWithDNS in apps/sim.1 parent e20d836 commit cb69d7a
43 files changed
Lines changed: 916 additions & 512 deletions
File tree
- apps
- desktop
- src
- main
- browser-agent
- test
- sim
- app
- api/tools
- onepassword
- sap_concur
- zoominfo
- desktop/launcher
- connectors/s3
- lib
- api/contracts/tools
- core/security
- mcp
- packages
- security
- src
- testing/src/mocks
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
137 | 137 | | |
138 | 138 | | |
139 | 139 | | |
140 | | - | |
| 140 | + | |
141 | 141 | | |
142 | 142 | | |
143 | 143 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
31 | 33 | | |
32 | 34 | | |
33 | 35 | | |
| |||
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
44 | | - | |
| 46 | + | |
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
| |||
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| 70 | + | |
68 | 71 | | |
69 | 72 | | |
70 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| 44 | + | |
42 | 45 | | |
43 | 46 | | |
44 | 47 | | |
| |||
118 | 121 | | |
119 | 122 | | |
120 | 123 | | |
121 | | - | |
| 124 | + | |
122 | 125 | | |
123 | 126 | | |
124 | 127 | | |
| |||
160 | 163 | | |
161 | 164 | | |
162 | 165 | | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | 166 | | |
168 | 167 | | |
169 | 168 | | |
| |||
191 | 190 | | |
192 | 191 | | |
193 | 192 | | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | 193 | | |
199 | 194 | | |
200 | 195 | | |
| |||
209 | 204 | | |
210 | 205 | | |
211 | 206 | | |
212 | | - | |
| 207 | + | |
213 | 208 | | |
214 | 209 | | |
215 | 210 | | |
| |||
249 | 244 | | |
250 | 245 | | |
251 | 246 | | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | 247 | | |
257 | 248 | | |
258 | 249 | | |
| |||
278 | 269 | | |
279 | 270 | | |
280 | 271 | | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
285 | 272 | | |
286 | 273 | | |
287 | 274 | | |
| |||
349 | 336 | | |
350 | 337 | | |
351 | 338 | | |
352 | | - | |
353 | | - | |
354 | | - | |
355 | | - | |
356 | 339 | | |
357 | 340 | | |
358 | 341 | | |
| |||
444 | 427 | | |
445 | 428 | | |
446 | 429 | | |
447 | | - | |
448 | | - | |
449 | | - | |
450 | | - | |
451 | 430 | | |
452 | 431 | | |
453 | 432 | | |
| |||
481 | 460 | | |
482 | 461 | | |
483 | 462 | | |
484 | | - | |
485 | | - | |
486 | | - | |
487 | | - | |
488 | 463 | | |
489 | 464 | | |
490 | 465 | | |
491 | 466 | | |
492 | 467 | | |
493 | 468 | | |
494 | 469 | | |
495 | | - | |
496 | | - | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
497 | 473 | | |
498 | 474 | | |
499 | 475 | | |
| |||
521 | 497 | | |
522 | 498 | | |
523 | 499 | | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
524 | 506 | | |
525 | 507 | | |
526 | 508 | | |
527 | | - | |
528 | | - | |
529 | | - | |
530 | 509 | | |
531 | 510 | | |
532 | 511 | | |
| |||
723 | 702 | | |
724 | 703 | | |
725 | 704 | | |
726 | | - | |
727 | | - | |
728 | | - | |
729 | | - | |
730 | 705 | | |
731 | 706 | | |
732 | 707 | | |
| |||
756 | 731 | | |
757 | 732 | | |
758 | 733 | | |
759 | | - | |
| 734 | + | |
760 | 735 | | |
761 | 736 | | |
762 | 737 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
5 | 12 | | |
6 | 13 | | |
7 | 14 | | |
| |||
11 | 18 | | |
12 | 19 | | |
13 | 20 | | |
| 21 | + | |
14 | 22 | | |
15 | 23 | | |
16 | 24 | | |
| |||
133 | 141 | | |
134 | 142 | | |
135 | 143 | | |
| 144 | + | |
| 145 | + | |
136 | 146 | | |
137 | 147 | | |
138 | 148 | | |
| |||
141 | 151 | | |
142 | 152 | | |
143 | 153 | | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
144 | 186 | | |
145 | 187 | | |
146 | 188 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
68 | 69 | | |
69 | 70 | | |
70 | 71 | | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
71 | 99 | | |
72 | 100 | | |
73 | | - | |
74 | 101 | | |
75 | 102 | | |
76 | | - | |
| 103 | + | |
77 | 104 | | |
78 | 105 | | |
79 | 106 | | |
| |||
97 | 124 | | |
98 | 125 | | |
99 | 126 | | |
100 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
101 | 130 | | |
102 | 131 | | |
103 | 132 | | |
| |||
0 commit comments