Skip to content

Commit 14be4bc

Browse files
pi0claude
andcommitted
fix(response): use HTML entity escaping for redirect body
`encodeURI` does not escape HTML metacharacters (`"`, `<`, `>`), allowing potential XSS via attribute breakout in the `<meta>` refresh tag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3a7536e commit 14be4bc

File tree

2 files changed

+8
-3
lines changed

2 files changed

+8
-3
lines changed

src/utils/response.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@ export function redirect(
4444
status: number = 302,
4545
statusText?: string,
4646
): HTTPResponse {
47-
const encodedLoc = encodeURI(location);
48-
const body = /* html */ `<html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}" /></head></html>`;
47+
const htmlLoc = location
48+
.replace(/&/g, "&amp;")
49+
.replace(/"/g, "&quot;")
50+
.replace(/</g, "&lt;")
51+
.replace(/>/g, "&gt;");
52+
const body = /* html */ `<html><head><meta http-equiv="refresh" content="0; url=${htmlLoc}" /></head></html>`;
4953
return new HTTPResponse(body, {
5054
status,
5155
statusText: statusText || (status === 301 ? "Moved Permanently" : "Found"),

test/utils.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ describeMatrix("utils", (t, { it, describe, expect }) => {
4949
expect(result.headers.get("location")).toBe(malicious);
5050
const body = await result.text();
5151
expect(body).not.toContain("<script>");
52-
expect(body).toContain("%3Cscript%3E");
52+
expect(body).toContain("&lt;script&gt;");
53+
expect(body).toContain("&quot;");
5354
});
5455
});
5556

0 commit comments

Comments
 (0)