Skip to content

Security: Core RPC server uses wildcard CORS (Access-Control-Allow-Origin: *) #2262

Description

@leighstillard

Summary

The in-process JSON-RPC HTTP server (src/core/jsonrpc.rs) sends Access-Control-Allow-Origin: * on every response, including authenticated /rpc calls. Combined with Access-Control-Allow-Headers: Content-Type, Authorization, any browser origin can issue authenticated cross-origin requests to the local RPC server if it possesses the per-launch bearer token.

Location: src/core/jsonrpc.rs:616-635 (with_cors_headers).

headers.insert(
    header::ACCESS_CONTROL_ALLOW_ORIGIN,
    HeaderValue::from_static("*"),
);

Threat model

The bearer token (OPENHUMAN_CORE_TOKEN) is the only thing protecting /rpc. The token is generated fresh per launch and is intended to stay inside the Tauri webview and the Rust process. But there are realistic paths for a token to end up visible to another origin:

  • A user pastes an error message or HAR file into a web tool / pastebin / chat.
  • A third-party script loaded by a future feature reads it from memory and beacons it out.
  • A debug session leaves the token in a screenshot, log share, or Sentry breadcrumb.
  • A CEF child webview running a third-party origin (Slack, Gmail, etc.) is compromised by a malicious script. Because the wildcard ACAO permits any origin, that script can directly call the local RPC.

With wildcard CORS, possession of the token is sufficient from any origin in any browser. The token should also be bound to origins we actually ship.

For an agentic assistant the RPC surface includes shell tool calls, memory access, credential reads, and sending messages on the user's behalf — so the blast radius of unauthorized RPC access is high.

Proposed fix

Replace the wildcard with an explicit allowlist:

  • tauri://localhost (macOS / Linux Tauri v2 webview)
  • http://tauri.localhost and https://tauri.localhost (Windows Tauri v2 webview)
  • http://127.0.0.1:*, http://localhost:*, http://[::1]:* (Vite dev server, E2E harnesses)
  • Optional comma-separated env override OPENHUMAN_CORE_ALLOWED_ORIGINS for debug harnesses

The middleware echoes the request's Origin back in Access-Control-Allow-Origin only when it matches the allowlist; otherwise the header is omitted and the browser blocks the response. Vary: Origin is added so caches respect per-origin responses. Requests without an Origin header (curl, non-browser) are unaffected.

Acceptance criteria

  • Cross-origin browser requests from any origin not on the allowlist are blocked (no Access-Control-Allow-Origin returned).
  • The Tauri webview (coreRpcClient.ts fetch path) continues to work on macOS, Linux, and Windows.
  • pnpm dev (Vite at http://localhost:1420) continues to work.
  • A unit test suite covers allowed Tauri origin, allowed localhost-with-port, disallowed origin, missing-origin request, and env-override.
  • Vary: Origin is set so the response is not incorrectly cached across origins.

Other security issues I'm looking into

  • Webhook signature / replay verification
  • Moving the encryption master key to OS keychain.
  • Prompt-injection enforcement vs. detection.
  • The general dual-channel trust model for scraped third-party content.

Activity

  1. Alexxigang commented on May 20, 2026

    @Alexxigang
    Contributor

    I traced this to with_cors_headers in src/core/jsonrpc.rs: it unconditionally emits Access-Control-Allow-Origin: * for both preflight and authenticated RPC responses. I am working on a fix that replaces the wildcard with an explicit origin allowlist (including Tauri + localhost dev origins), adds Vary: Origin, and lands focused regression tests for allowed, disallowed, missing-origin, and env-override cases.

  2. leighstillard commented on May 20, 2026

    @leighstillard
    ContributorAuthor

    @Alexxigang sorry mate I just beat you to it

  3. Alexxigang commented on May 20, 2026

    @Alexxigang
    Contributor

    Update: I found active PR #2266 covering this issue and will not open a duplicate PR. I already validated the same root cause locally, but I am stepping back here and will move to another open issue instead.

  4. moved this from Todo to In progress in Team Openhumanon May 20, 2026
  5. moved this from In progress to Done in Team Openhumanon May 20, 2026
  6. added a commit that references this issue on May 20, 2026
    92682d0
  7. added a commit that references this issue on May 20, 2026
    0311d81
  8. added 2 commits that reference this issue on May 21, 2026
    90e8cd6
    b6a5f8d
  9. added 2 commits that reference this issue on May 22, 2026
    aa57a5c
    f8454d6
  10. added 2 commits that reference this issue on May 23, 2026
    953feaa
    6f2af70
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions