mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-26 16:41:49 +00:00
fix(browser): land PR #11880 decodeURIComponent guardrails
Guard malformed percent-encoding in relay target routes and browser dispatcher params, add regression tests, and update changelog. Landed from contributor @Yida-Dev (PR #11880). Co-authored-by: Yida-Dev <reyifeijun@gmail.com>
This commit is contained in:
@@ -208,6 +208,18 @@ describe("chrome extension relay server", () => {
|
||||
expect(err.message).toContain("401");
|
||||
});
|
||||
|
||||
it("returns 400 for malformed percent-encoding in target action routes", async () => {
|
||||
const port = await getFreePort();
|
||||
cdpUrl = `http://127.0.0.1:${port}`;
|
||||
await ensureChromeExtensionRelayServer({ cdpUrl });
|
||||
|
||||
const res = await fetch(`${cdpUrl}/json/activate/%E0%A4%A`, {
|
||||
headers: relayAuthHeaders(cdpUrl),
|
||||
});
|
||||
expect(res.status).toBe(400);
|
||||
expect(await res.text()).toContain("invalid targetId encoding");
|
||||
});
|
||||
|
||||
it("deduplicates concurrent relay starts for the same requested port", async () => {
|
||||
const port = await getFreePort();
|
||||
cdpUrl = `http://127.0.0.1:${port}`;
|
||||
|
||||
@@ -476,7 +476,14 @@ export async function ensureChromeExtensionRelayServer(opts: {
|
||||
if (!match || (req.method !== "GET" && req.method !== "PUT")) {
|
||||
return false;
|
||||
}
|
||||
const targetId = decodeURIComponent(match[1] ?? "").trim();
|
||||
let targetId = "";
|
||||
try {
|
||||
targetId = decodeURIComponent(match[1] ?? "").trim();
|
||||
} catch {
|
||||
res.writeHead(400);
|
||||
res.end("invalid targetId encoding");
|
||||
return true;
|
||||
}
|
||||
if (!targetId) {
|
||||
res.writeHead(400);
|
||||
res.end("targetId required");
|
||||
|
||||
@@ -23,6 +23,15 @@ vi.mock("./index.js", () => {
|
||||
res.json({ ok: true });
|
||||
},
|
||||
);
|
||||
app.get(
|
||||
"/echo/:id",
|
||||
async (
|
||||
req: { params?: Record<string, string> },
|
||||
res: { json: (body: unknown) => void },
|
||||
) => {
|
||||
res.json({ id: req.params?.id ?? null });
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -46,4 +55,19 @@ describe("browser route dispatcher (abort)", () => {
|
||||
body: { error: expect.stringContaining("timed out") },
|
||||
});
|
||||
});
|
||||
|
||||
it("returns 400 for malformed percent-encoding in route params", async () => {
|
||||
const { createBrowserRouteDispatcher } = await import("./dispatcher.js");
|
||||
const dispatcher = createBrowserRouteDispatcher({} as BrowserRouteContext);
|
||||
|
||||
await expect(
|
||||
dispatcher.dispatch({
|
||||
method: "GET",
|
||||
path: "/echo/%E0%A4%A",
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
status: 400,
|
||||
body: { error: expect.stringContaining("invalid path parameter encoding") },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,7 +87,14 @@ export function createBrowserRouteDispatcher(ctx: BrowserRouteContext) {
|
||||
for (const [idx, name] of match.paramNames.entries()) {
|
||||
const value = exec[idx + 1];
|
||||
if (typeof value === "string") {
|
||||
params[name] = decodeURIComponent(value);
|
||||
try {
|
||||
params[name] = decodeURIComponent(value);
|
||||
} catch {
|
||||
return {
|
||||
status: 400,
|
||||
body: { error: `invalid path parameter encoding: ${name}` },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user