Skip to content

WebSockets, WebRTC, and Peering - #54

Merged
martindale merged 106 commits into
masterfrom
feature/v0.1.0-RC1
Apr 22, 2026
Merged

martindale merged 106 commits into
masterfrom
feature/v0.1.0-RC1

Conversation

@martindale

@martindale martindale commented May 14, 2025

Copy link
Copy Markdown
Member

General pass on WebSockets.

Improvements:

  • Finalize HTTP 402 Handler
  • Finalize Fabric-over-WebRTC
  • Formalize Message specificiation

Release Gate:

  • Downstream @fabric/browser and/or @fabric/extension implement passing tests for auth flow

Note

High Risk
Adds new authentication token parsing/verification and role-authorization logic, plus a new payments gate that can block requests with 402; these changes affect security and request handling behavior. CI/runtime upgrade to Node 22 may surface compatibility issues in dependencies/tests.

Overview
Upgrades CI/runtime to Node.js 22.14.0 by updating .nvmrc, .travis.yml, and moving GitHub Actions to actions/setup-node@v4.

Introduces bearer-token based auth context in middlewares/auth.js: verifies a request.token using a SHA-256 signature scheme with timing-safe comparison, sets request.authenticated, and exposes decoded tokenHeader/tokenPayload plus tokenError. contracts/hasRole.js is updated to authorize via tokenPayload.role or tokenPayload.roles (and removes noisy debug logging).

Adds a new payments middleware that creates a Bitcoin invoice and returns 402 Payment Required (currently unconditional), and includes minor UI/dev changes: adds API.md documentation output, cleans a bridge debug log, and adds _handleRemoteReady in FabricBridge that fetches btc_getbalances on remote readiness.

Written by Cursor Bugbot for commit c692d0b. Configure here.

Summary by CodeRabbit

  • New Features
    • Enhanced HTTP server (JSON‑RPC, WebSocket token gating, SPA/static behavior), deterministic avatars and web avatar component, distributed-execution HTTP endpoints, CLI/server options, payments middleware
  • Bug Fixes
    • Hardening: safer lifecycle/shutdown, improved auth/token checks, role authorization fixes, more defensive remote/bridge handling
  • Tests
    • New standards, WebSocket/JSON‑RPC suites and fixtures; many test helpers added
  • Documentation
    • New API, production/release guides, marketing overview, globals index, README updates
  • Chores
    • CI workflow added, Node runtime bumped, package.json scripts and dependency updates

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Security review complete for PR #54.

Validated prior automation findings against current diff:

  • The previous bearer-token forgery issue no longer applies: verifyBearerToken now fails closed when no secret is configured (missing_secret) and does not use a hardcoded fallback secret.
  • The prior WebSocket JSONCall auth-bypass finding no longer applies: the JSONCall path now checks transport authorization before invoking _handleCall.

No high-confidence medium/high/critical vulnerabilities were confirmed in the added/modified code paths reviewed.

Slack summary: PR #54 security pass completed; no medium+ vulnerabilities currently confirmed.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Revalidated prior security findings from earlier automation runs against current HEAD:

  • The hardcoded bearer-token fallback secret issue in middlewares/auth.js is fixed.
  • The earlier unconditional WebSocket JSONCall auth bypass is partially mitigated, but one medium auth-control issue remains.

Slack summary: 1 medium security finding remains in WebSocket auth gating (types/server.js) due fail-open behavior when client-token auth is marked required but no secret is configured.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread types/server.js Outdated
const wsCfg = this.settings.websocket || {};
const secret = wsCfg.clientToken || wsCfg.sharedSecret || null;
const required = wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1;
if (!required || !secret) return true;

ghost Apr 7, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium severity – fail-open WebSocket auth control.
When requireClientToken is enabled but clientToken/sharedSecret is missing, this branch returns true and accepts the connection. That lets unauthenticated clients open WebSocket sessions and hit message handlers without the intended token boundary (including state-changing handlers and JSONCall when RPC auth is off). This should fail closed (return false) when token auth is required but no secret is configured.

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Security review update after validating prior unresolved security threads against current head.

Findings (current)

  1. High – Unauthenticated WebSocket JSONCall can execute registered RPC methods when jsonRpc auth mode is not explicitly enabled.
  2. Medium – WebSocket client-token enforcement is fail-open when requireClientToken=true but token secret is missing/misconfigured.

Validation notes on prior security findings

  • Prior hardcoded bearer fallback-secret finding in middlewares/auth.js no longer applies on this head.
  • Remaining issues above are still exploitable with plausible network attack paths.

Slack summary: PR #54 security review -> REQUEST_CHANGES. 2 active vulns: (1) High unauthenticated WS JSONCall method execution path, (2) Medium fail-open WS token gate on misconfiguration. Hardcoded bearer fallback secret issue appears fixed.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread types/server.js
}

const kernel = new Actor(jsonCallPayload);
const result = await server._handleCall({

ghost Apr 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High: attacker-controlled JSONCall input reaches _handleCall(...) without guaranteed auth. socket._fabricJsonRpcTransportAuthorized is set to true unless jsonRpc.enabled===true && jsonRpc.requireAuth===true, so default/legacy configs allow unauthenticated WebSocket clients to invoke registered RPC handlers. Impact: authz bypass for state-changing/admin methods exposed via _registerMethod.

Comment thread types/server.js Outdated
const wsCfg = this.settings.websocket || {};
const secret = wsCfg.clientToken || wsCfg.sharedSecret || null;
const required = wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1;
if (!required || !secret) return true;

ghost Apr 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: fail-open token boundary. When requireClientToken is enabled but clientToken/sharedSecret is absent or misconfigured, this returns true and accepts the connection. Impact: operators can believe WS token auth is enforced while unauthenticated clients are still admitted.

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Security review update for PR #54:

Validated prior unresolved security findings against the latest head. Previously reported hardcoded bearer fallback-secret and unauthenticated JSON-RPC transport issues have been addressed. However, two authentication-boundary issues still allow unauthenticated WebSocket access in realistic configurations.

Slack summary: Requesting changes due to 1 high and 1 medium auth bypass risk in types/server.js (WebSocket token enforcement can be bypassed when sharedSecret is used or when token enforcement is enabled without a configured secret).

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread types/server.js Outdated
});
const wsOpts = { server: this.http };
const wsCfg = this.settings.websocket || {};
if (wsCfg.clientToken && (wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1)) {

ghost Apr 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High severity – WebSocket auth bypass via config mismatch.

Handshake auth is only enabled when wsCfg.clientToken is present, but this PR also treats wsCfg.sharedSecret as a valid token secret in _verifyWebSocketClient and _isJsonRpcTransportAuthorized. A deployment that sets websocket.requireClientToken=true with websocket.sharedSecret will not attach verifyClient, so unauthenticated clients can still complete the WebSocket handshake and reach message handlers (POST/PATCH/Call) without presenting a token.

Comment thread types/server.js Outdated
const wsCfg = this.settings.websocket || {};
const secret = wsCfg.clientToken || wsCfg.sharedSecret || null;
const required = wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1;
if (!required || !secret) return true;

ghost Apr 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium severity – fail-open token gate when auth is required.

_verifyWebSocketClient returns true when requireClientToken is enabled but the secret is missing (!required || !secret). This fails open instead of denying access, so a misconfigured deployment silently accepts unauthenticated WebSocket clients that can invoke server message handlers and mutate/read application state.

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Security review result: 1 High severity vulnerability remains after re-validating prior security threads.

  • Revalidated and no longer reproducible: earlier hardcoded bearer-secret issue in middlewares/auth.js (now fails closed when secret is missing).
  • Still reproducible: WebSocket client-token enforcement can be bypassed when sharedSecret is configured without clientToken.

Slack summary: PR #54 security review -> 1 High finding (WebSocket auth bypass via config mismatch in handshake guard). Requesting changes.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread types/server.js Outdated
});
const wsOpts = { server: this.http };
const wsCfg = this.settings.websocket || {};
if (wsCfg.clientToken && (wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1)) {

ghost Apr 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High – authentication bypass: this guard only enables verifyClient when websocket.clientToken is set, but _verifyWebSocketClient() also accepts websocket.sharedSecret. If deployers set requireClientToken: true with only sharedSecret, handshake verification is never attached, so unauthenticated attackers can open WebSocket connections and invoke privileged message handlers (state-changing POST/PATCH, and JSONCall where transport auth is not otherwise required).

ghost left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validated prior security-review threads against the current PR head and re-tested the auth paths. One high-confidence vulnerability still applies.

Please address the inline finding before merge; it allows unauthenticated WebSocket access in a common token-auth configuration.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread types/server.js Outdated
});
const wsOpts = { server: this.http };
const wsCfg = this.settings.websocket || {};
if (wsCfg.clientToken && (wsCfg.requireClientToken === true || wsCfg.requireClientToken === '1' || wsCfg.requireClientToken === 1)) {

ghost Apr 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High severity — WebSocket authentication bypass. verifyClient is only enabled when wsCfg.clientToken is set, but the verifier itself accepts either wsCfg.clientToken or wsCfg.sharedSecret as the token secret. With websocket.requireClientToken=true and only websocket.sharedSecret configured, the handshake verifier is never attached, so unauthenticated clients can open WebSocket sessions and reach message handlers (POST/PATCH/Call, and JSONCall when transport auth is not otherwise enforced).

@martindale
martindale merged commit b20d4d8 into master Apr 22, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 25, 2026
4 tasks
@martindale martindale moved this from Computing to Deploying in #meta May 4, 2026
@coderabbitai coderabbitai Bot mentioned this pull request May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Deploying

Development

Successfully merging this pull request may close these issues.

HTTP Output Stream Defaults

2 participants