Skip to content

Security: engrtitooo/buddy-webmcp

SECURITY.md

Security and privacy

Assets

  • User intent and personal agent rules
  • Authority to invoke website actions
  • Structured tool arguments and results
  • Server-side model credentials
  • Integrity of approval decisions

Trust boundaries

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.

Controls

  • 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.postMessage RPC, or privileged extension API exposure
  • Explicit WebMCP feature detection and allowed methods
  • Native RegisteredTool objects 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 reach executeTool
  • 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 complete chrome-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 private allowlist alternative
  • 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

Residual risks

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.

Reporting

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.

There aren't any published security advisories