fix(security): enforce sandbox bridge auth

This commit is contained in:
Peter Steinberger
2026-02-14 13:17:41 +01:00
parent 4711a943e3
commit 6dd6bce997
8 changed files with 108 additions and 5 deletions

View File

@@ -4,7 +4,9 @@ import type { AddressInfo } from "node:net";
import express from "express";
import type { ResolvedBrowserConfig } from "./config.js";
import type { BrowserRouteRegistrar } from "./routes/types.js";
import { isLoopbackHost } from "../gateway/net.js";
import { safeEqualSecret } from "../security/secret-equal.js";
import { deleteBridgeAuthForPort, setBridgeAuthForPort } from "./bridge-auth-registry.js";
import { registerBrowserRoutes } from "./routes/index.js";
import {
type BrowserServerState,
@@ -89,6 +91,9 @@ export async function startBrowserBridgeServer(params: {
onEnsureAttachTarget?: (profile: ProfileContext["profile"]) => Promise<void>;
}): Promise<BrowserBridge> {
const host = params.host ?? "127.0.0.1";
if (!isLoopbackHost(host)) {
throw new Error(`bridge server must bind to loopback host (got ${host})`);
}
const port = params.port ?? 0;
const app = express();
@@ -109,6 +114,9 @@ export async function startBrowserBridgeServer(params: {
const authToken = params.authToken?.trim() || undefined;
const authPassword = params.authPassword?.trim() || undefined;
if (!authToken && !authPassword) {
throw new Error("bridge server requires auth (authToken/authPassword missing)");
}
if (authToken || authPassword) {
app.use((req, res, next) => {
if (isAuthorizedBrowserRequest(req, { token: authToken, password: authPassword })) {
@@ -142,11 +150,21 @@ export async function startBrowserBridgeServer(params: {
state.port = resolvedPort;
state.resolved.controlPort = resolvedPort;
setBridgeAuthForPort(resolvedPort, { token: authToken, password: authPassword });
const baseUrl = `http://${host}:${resolvedPort}`;
return { server, port: resolvedPort, baseUrl, state };
}
export async function stopBrowserBridgeServer(server: Server): Promise<void> {
try {
const address = server.address() as AddressInfo | null;
if (address?.port) {
deleteBridgeAuthForPort(address.port);
}
} catch {
// ignore
}
await new Promise<void>((resolve) => {
server.close(() => resolve());
});