Skip to content

Commit 56096eb

Browse files
fix(browser): report malformed relay CDP frames (#102070)
* fix(browser): report malformed relay CDP frames * refactor(browser): streamline relay frame validation --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 61a7fc5 commit 56096eb

2 files changed

Lines changed: 48 additions & 5 deletions

File tree

extensions/browser/src/browser/extension-relay/relay-bridge.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,34 @@ describe("ExtensionRelayBridge", () => {
324324
expect(bridge.extensionConnected).toBe(false);
325325
});
326326

327+
it("reports malformed CDP client JSON instead of leaving the client waiting", () => {
328+
const bridge = new ExtensionRelayBridge();
329+
const client = new FakeSocket();
330+
const cdp = bridge.attachCdpClientSocket(client);
331+
332+
cdp.onMessage("{");
333+
334+
expect(client.frames()).toEqual([
335+
{ id: null, error: { code: -32700, message: "Parse error" } },
336+
]);
337+
});
338+
339+
it("reports invalid CDP client requests instead of leaving the client waiting", () => {
340+
const bridge = new ExtensionRelayBridge();
341+
const client = new FakeSocket();
342+
const cdp = bridge.attachCdpClientSocket(client);
343+
344+
cdp.onMessage(JSON.stringify({ id: 7, sessionId: "session-1", params: {} }));
345+
346+
expect(client.frames()).toEqual([
347+
{
348+
id: 7,
349+
sessionId: "session-1",
350+
error: { code: -32600, message: "Invalid request" },
351+
},
352+
]);
353+
});
354+
327355
it("reaps child sessions when a tab leaves the group (no stale routing)", async () => {
328356
const bridge = new ExtensionRelayBridge();
329357
const { handlers } = wireExtension(bridge);

extensions/browser/src/browser/extension-relay/relay-bridge.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ type ExtensionIdentity = {
7474
extensionVersion: string;
7575
};
7676

77-
function toErrorPayload(id: number, sessionId: string | undefined, message: string, code = -32000) {
77+
function toErrorPayload(
78+
id: number | null,
79+
sessionId: string | undefined,
80+
message: string,
81+
code = -32000,
82+
): string {
7883
return JSON.stringify({ id, ...(sessionId ? { sessionId } : {}), error: { code, message } });
7984
}
8085

@@ -494,16 +499,26 @@ export class ExtensionRelayBridge {
494499
const client: CdpClientState = { socket, autoAttach: false, announcedSessions: new Set() };
495500
this.clients.add(client);
496501
const onMessage = (raw: string) => {
497-
let request: CdpRequest;
502+
let parsed: unknown;
498503
try {
499-
request = JSON.parse(raw) as CdpRequest;
504+
parsed = JSON.parse(raw);
500505
} catch {
506+
client.socket.send(toErrorPayload(null, undefined, "Parse error", -32700));
501507
return;
502508
}
503-
if (typeof request?.id !== "number" || typeof request?.method !== "string") {
509+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
510+
client.socket.send(toErrorPayload(null, undefined, "Invalid request", -32600));
504511
return;
505512
}
506-
void this.handleCdpRequest(client, request);
513+
const request = parsed as Record<string, unknown>;
514+
if (typeof request.id !== "number" || typeof request.method !== "string") {
515+
const id = typeof request.id === "number" ? request.id : null;
516+
const sessionId = typeof request.sessionId === "string" ? request.sessionId : undefined;
517+
// Flat CDP routes responses by sessionId before matching the request id.
518+
client.socket.send(toErrorPayload(id, sessionId, "Invalid request", -32600));
519+
return;
520+
}
521+
void this.handleCdpRequest(client, request as CdpRequest);
507522
};
508523
const onClose = () => {
509524
this.clients.delete(client);

0 commit comments

Comments
 (0)