#2648·BrowserOS

Originless localhost GETs can read protected conversation and schedule data

Author: avinashgolaCreated Sep 9, 2026Updated Sep 9, 2026

Summary

Protected app routes allow originless GET requests as long as they come from loopback. That means a local process can read protected BrowserOS data without presenting an extension/app origin.

This affects routes that return private app state, including full conversation bodies and scheduled job run results.

Evidence

packages/browseros-agent/apps/server/src/api/utils/request-auth.ts treats originless GET, HEAD, and OPTIONS requests as trusted app requests after the loopback/host checks pass:

typescript
const origin = c.req.header('origin')
if (origin) return isTrustedAppOrigin(origin)

return ['GET', 'HEAD', 'OPTIONS'].includes(c.req.method)

Those checks are used on protected route prefixes in packages/browseros-agent/apps/server/src/api/routes/index.ts:

typescript
.use('/conversations/*', requireTrustedAppOrigin())
.use('/providers/*', requireTrustedAppOrigin())
.use('/scheduled-jobs/*', requireTrustedAppOrigin())
.use('/scheduled-job-runs/*', requireTrustedAppOrigin())

The routes include read endpoints that return private data:

  • GET /conversations/:conversationId returns the full messages blob from packages/browseros-agent/apps/server/src/api/routes/conversations.ts
  • GET /scheduled-job-runs/:runId returns stored run result, finalResult, executionLog, toolCalls, and error from packages/browseros-agent/apps/server/src/api/routes/scheduled-job-runs.ts

There are tests showing the protected routes reject when no Bun server.requestIP context is present, but there does not appear to be coverage for a real loopback request with no Origin header.

Repro sketch

From a local process on the same machine, request a protected read route without an Origin header, for example:

bash
curl -H 'Host: 127.0.0.1:<port>' http://127.0.0.1:<port>/conversations/<conversation-id>

Because this is a loopback GET with no Origin, isTrustedAppRequest() returns true and the route can serve the protected data.

Expected

Protected app-state routes should require a trusted BrowserOS app/extension origin even for reads, or split genuinely public/status reads onto separate unprotected routes.

Actual

Originless loopback reads are accepted for protected route prefixes that expose user conversation and scheduled-task data.