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
refactor(security): one DNS resolver for every SSRF guard, checking all addresses
Five independent `dns.lookup` bodies existed — four in apps/sim
(validateUrlWithDNS, the database-host check, MCP domain-check, 1Password
Connect) and one in apps/desktop's agent url-guard. The four in apps/sim were
copy-paste identical, and two properties diverged in ways that mattered:
They classified ONE address. `resolved.find(family === 4) ?? resolved[0]`
picked an address to pin and then judged only that one, so a host publishing
both a public and a private record passed whenever the public record sorted
first. That is record order, not policy, and validateUrlWithDNS alone is reached
from ~70 call sites. Now every address is classified and the IPv4-preferred one
is still what gets returned to pin — the pinning rationale (Happy Eyeballs
fallback is stripped, and a pinned IPv6 address hangs on IPv4-only egress) is
untouched.
They had no deadline. Only the desktop copy bounded the lookup, so a hung
resolver could hold an apps/sim request handler open indefinitely. The shared
helper carries the 5s deadline, the swallowed late rejection, and the always
cleared timer.
`resolveHostAddresses` lands in `@sim/security/dns` as its own subpath, so the
`node:dns` dependency reaches only the servers that import it — apps/realtime
pulls `@sim/security/compare` and nothing else, and the prune graph is unchanged
at 14 workspaces.
Two lookups deliberately stay as they are: `createSsrfGuardedLookup` is a
socket-connect `LookupFunction` that needs raw entries with their family and
already validates every address, and desktop's per-host verdict cache keeps its
own loopback policy on top of the shared resolver.
The localhost carve-out is tightened as a consequence: it applies only when
every record is loopback, so `localhost` that also resolves to the LAN no longer
rides it.
0 commit comments