- User intent and personal agent rules
- Authority to invoke website actions
- Structured tool arguments and results
- Server-side model credentials
- Integrity of approval decisions
The webpage, tool names, descriptions, schemas, and results are untrusted. The extension UI and approval policy are trusted extension code. The optional API proxy is a separate server trust boundary.
- Isolated Manifest V3 content script and closed Shadow DOM
- Styles are embedded in the closed Shadow DOM; page CSS cannot restyle Buddy's trusted approval UI
- A least-privilege service worker owns the single build-time API origin; content scripts cannot choose a destination
- No page-visible bridge,
window.postMessageRPC, or privileged extension API exposure - Explicit WebMCP feature detection and allowed methods
- Native
RegisteredToolobjects never serialized to page code - Execution only when the reviewed tool-set revision is still current
- Tool descriptions are treated as data; the remote planner is instructed to ignore embedded instructions
- The OpenAI Structured Output has one closed object envelope; the model emits arguments only as a bounded JSON string and cannot emit risk or call IDs
- Server and client validate every selected tool name, the server parses
argsJson, and Ajv validates arguments against the site's current JSON Schema before execution; invalid calls become bounded repair feedback and never reachexecuteTool - Risk classification and call IDs are always generated by deterministic Buddy code
- One-action iterations, a ten-turn ceiling, duplicate-call detection, abort propagation, and revision checks bound agent autonomy
- Consequential risk classes require approval by default; deletion is blocked by default
- Approval shows complete human-readable values; raw JSON and raw tool names are Developer Mode-only, and Cancel never invokes the gated tool
- No API key in browser code; development uses loopback, production uses the fixed Railway HTTPS default with a build guard. The proxy has an exact web-origin allowlist, originless-request denial, bounded inputs, provider timeouts, safe request IDs/logs, an auth-verifier interface, and replaceable per-client rate limiting. Production startup rejects missing secrets, localhost/insecure or malformed origins, and originless mode
- The public judging service explicitly enables
BUDDY_EXTENSION_ORIGIN_POLICY=chrome-extensions: only completechrome-extension://[a-p]{32}origins are accepted beyond the exact allowlist. Normal web origins remain restricted. Any installed extension or non-browser client could use this public demo, so this policy is not authentication. Text/voice quota buckets cannot be reset by rotating extension IDs. See PRODUCTION.md for rationale, proxy quota limitations, and the privateallowlistalternative - Realtime accepts only bounded audio SDP through the fixed service-worker destination. The API owns model, voice, instructions, VAD, transcription, and the sole internal intent function; it applies separate session-creation limiting and returns no credential or arbitrary provider configuration
- Realtime intent re-enters the existing agent loop. The model never receives native page handles, executable tool names, local risk authority, or approval authority; visual approval and current-inventory checks remain deterministic extension controls
- Microphone capture requires an explicit waveform-button gesture. Device loss, speech inactivity, panel/page lifecycle, bounded reconnect exhaustion, and explicit stop release tracks, peer/data channel, remote audio, analyser, listeners, and timers
- No full-page capture, browsing history, cookies, or hidden DOM automation
- Developer diagnostics are opt-in and not persisted
WebMCP annotations are hints supplied by an untrusted site, so Buddy does not let readOnlyHint override obviously consequential names. A malicious site can still lie in its implementation or return adversarial text; users should judge the current site identity shown in Buddy's header. Model prompt-injection defenses reduce but cannot eliminate probabilistic model risk, so provider output is runtime-validated and approval remains a deterministic layer outside the model.
The optional model proxy is safe for local development by default. Its in-memory limiter is not a distributed production control. Do not expose it directly to the public internet: place public deployments behind authenticated infrastructure with durable distributed rate limits, abuse controls, TLS, secret storage, and provider-usage monitoring.
For unified WebRTC, the browser owns the media connection after a successful bootstrap. The server chooses the advertised session cap, but the trusted extension enforces that cap and the speech-idle timeout. A public deployment must not rely on client cleanup, CORS, or the in-memory bootstrap limiter as authoritative spend controls; use gateway identity/attestation, a distributed limiter, and provider budgets or alerts.
Please report vulnerabilities privately to the repository maintainers before public disclosure. Include affected version, reproduction steps, expected impact, and whether a malicious site is required.