Skip to content

Commit 8959cb9

Browse files
bytaesuhimself65
authored andcommitted
fix(cookies): use lookahead heuristic for splitting Set-Cookie headers (#8301)
1 parent 4b97412 commit 8959cb9

File tree

2 files changed

+68
-25
lines changed

2 files changed

+68
-25
lines changed

packages/better-auth/src/cookies/cookie-utils.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,45 +27,43 @@ export function stripSecureCookiePrefix(cookieName: string): string {
2727
}
2828

2929
/**
30-
* Split `Set-Cookie` header, handling commas in `Expires` dates.
30+
* Split a comma-joined `Set-Cookie` header string into individual cookies.
3131
*/
3232
export function splitSetCookieHeader(setCookie: string): string[] {
3333
if (!setCookie) return [];
3434

3535
const result: string[] = [];
36-
let current = "";
36+
let start = 0;
3737
let i = 0;
3838

3939
while (i < setCookie.length) {
40-
const c = setCookie[i];
41-
42-
if (c === ",") {
43-
const lower = current.toLowerCase();
44-
if (lower.includes("expires=") && !lower.includes("gmt")) {
45-
current += c;
46-
i++;
47-
} else {
48-
const trimmed = current.trim();
49-
if (trimmed) {
50-
result.push(trimmed);
51-
}
52-
current = "";
53-
i++;
54-
if (i < setCookie.length && setCookie[i] === " ") {
55-
i++;
56-
}
40+
if (setCookie[i] === ",") {
41+
let j = i + 1;
42+
while (j < setCookie.length && setCookie[j] === " ") j++;
43+
while (
44+
j < setCookie.length &&
45+
setCookie[j] !== "=" &&
46+
setCookie[j] !== ";" &&
47+
setCookie[j] !== ","
48+
) {
49+
j++;
50+
}
51+
52+
if (j < setCookie.length && setCookie[j] === "=") {
53+
const part = setCookie.slice(start, i).trim();
54+
if (part) result.push(part);
55+
start = i + 1;
56+
while (start < setCookie.length && setCookie[start] === " ") start++;
57+
i = start;
58+
continue;
5759
}
58-
continue;
5960
}
6061

61-
current += c;
6262
i++;
6363
}
6464

65-
const trimmed = current.trim();
66-
if (trimmed) {
67-
result.push(trimmed);
68-
}
65+
const last = setCookie.slice(start).trim();
66+
if (last) result.push(last);
6967

7068
return result;
7169
}

packages/better-auth/src/cookies/cookies.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,51 @@ describe("cookie-utils parseSetCookieHeader", () => {
237237
expect(map.get("token")?.value).toBe("abc");
238238
expect(map.get("token")?.expires).toBeUndefined();
239239
});
240+
241+
it("handles Expires when cookie value contains gmt substring", () => {
242+
const map = parseSetCookieHeader(
243+
"session_data=testsessiondata; Path=/; Expires=Mon, 02 Mar 2026 05:42:16 GMT; Max-Age=300; Secure; HttpOnly; SameSite=lax",
244+
);
245+
246+
expect(map.get("session_data")?.value).toBe("testsessiondata");
247+
expect(map.get("session_data")?.expires).toEqual(
248+
new Date("Mon, 02 Mar 2026 05:42:16 GMT"),
249+
);
250+
});
251+
252+
it("handles non-standard Expires=0", () => {
253+
const map = parseSetCookieHeader("a=1; Expires=0, b=2");
254+
expect(map.get("a")?.value).toBe("1");
255+
expect(map.get("b")?.value).toBe("2");
256+
});
257+
258+
it("handles RFC 850 date format", () => {
259+
const map = parseSetCookieHeader(
260+
"a=1; Expires=Sunday, 06-Nov-94 08:49:37 GMT, b=2",
261+
);
262+
expect(map.get("a")?.value).toBe("1");
263+
expect(map.get("b")?.value).toBe("2");
264+
});
265+
266+
it("handles asctime date format (no comma in date)", () => {
267+
const map = parseSetCookieHeader(
268+
"a=1; Expires=Sun Nov 6 08:49:37 1994, b=2",
269+
);
270+
expect(map.get("a")?.value).toBe("1");
271+
expect(map.get("b")?.value).toBe("2");
272+
});
273+
274+
it("handles mixed cookies with and without Expires", () => {
275+
const map = parseSetCookieHeader(
276+
"a=1; Path=/; HttpOnly, b=2; Expires=Mon, 01 Jan 2026 00:00:00 GMT; Secure, c=3; SameSite=Lax",
277+
);
278+
expect(map.get("a")?.value).toBe("1");
279+
expect(map.get("b")?.value).toBe("2");
280+
expect(map.get("b")?.expires).toEqual(
281+
new Date("Mon, 01 Jan 2026 00:00:00 GMT"),
282+
);
283+
expect(map.get("c")?.value).toBe("3");
284+
});
240285
});
241286

242287
describe("cookie-utils stripSecureCookiePrefix", () => {

0 commit comments

Comments
 (0)