Skip to content

Commit e100428

Browse files
authoredOct 1, 2024··
fix: narrow the validation of cookies to match RFC6265 (#167)
1 parent 26031e3 commit e100428

File tree

2 files changed

+59
-9
lines changed

2 files changed

+59
-9
lines changed
 

‎index.js

+55-9
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,60 @@ exports.serialize = serialize;
2323
var __toString = Object.prototype.toString
2424

2525
/**
26-
* RegExp to match field-content in RFC 7230 sec 3.2
26+
* RegExp to match cookie-name in RFC 6265 sec 4.1.1
27+
* This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
28+
* which has been replaced by the token definition in RFC 7230 appendix B.
2729
*
28-
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
29-
* field-vchar = VCHAR / obs-text
30-
* obs-text = %x80-FF
30+
* cookie-name = token
31+
* token = 1*tchar
32+
* tchar = "!" / "#" / "$" / "%" / "&" / "'" /
33+
* "*" / "+" / "-" / "." / "^" / "_" /
34+
* "`" / "|" / "~" / DIGIT / ALPHA
3135
*/
3236

33-
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
37+
var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
38+
39+
/**
40+
* RegExp to match cookie-value in RFC 6265 sec 4.1.1
41+
*
42+
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
43+
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
44+
* ; US-ASCII characters excluding CTLs,
45+
* ; whitespace DQUOTE, comma, semicolon,
46+
* ; and backslash
47+
*/
48+
49+
var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
50+
51+
/**
52+
* RegExp to match domain-value in RFC 6265 sec 4.1.1
53+
*
54+
* domain-value = <subdomain>
55+
* ; defined in [RFC1034], Section 3.5, as
56+
* ; enhanced by [RFC1123], Section 2.1
57+
* <subdomain> = <label> | <subdomain> "." <label>
58+
* <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]
59+
* Labels must be 63 characters or less.
60+
* 'let-dig' not 'letter' in the first char, per RFC1123
61+
* <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
62+
* <let-dig-hyp> = <let-dig> | "-"
63+
* <let-dig> = <letter> | <digit>
64+
* <letter> = any one of the 52 alphabetic characters A through Z in
65+
* upper case and a through z in lower case
66+
* <digit> = any one of the ten digits 0 through 9
67+
*/
68+
69+
var domainValueRegExp = /^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
70+
71+
/**
72+
* RegExp to match path-value in RFC 6265 sec 4.1.1
73+
*
74+
* path-value = <any CHAR except CTLs or ";">
75+
* CHAR = %x01-7F
76+
* ; defined in RFC 5234 appendix B.1
77+
*/
78+
79+
var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
3480

3581
/**
3682
* Parse a cookie header.
@@ -116,13 +162,13 @@ function serialize(name, val, options) {
116162
throw new TypeError('option encode is invalid');
117163
}
118164

119-
if (!fieldContentRegExp.test(name)) {
165+
if (!cookieNameRegExp.test(name)) {
120166
throw new TypeError('argument name is invalid');
121167
}
122168

123169
var value = enc(val);
124170

125-
if (value && !fieldContentRegExp.test(value)) {
171+
if (value && !cookieValueRegExp.test(value)) {
126172
throw new TypeError('argument val is invalid');
127173
}
128174

@@ -139,15 +185,15 @@ function serialize(name, val, options) {
139185
}
140186

141187
if (opt.domain) {
142-
if (!fieldContentRegExp.test(opt.domain)) {
188+
if (!domainValueRegExp.test(opt.domain)) {
143189
throw new TypeError('option domain is invalid');
144190
}
145191

146192
str += '; Domain=' + opt.domain;
147193
}
148194

149195
if (opt.path) {
150-
if (!fieldContentRegExp.test(opt.path)) {
196+
if (!pathValueRegExp.test(opt.path)) {
151197
throw new TypeError('option path is invalid');
152198
}
153199

‎test/serialize.js

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe('cookie.serialize(name, value)', function () {
2020
it('should throw for invalid name', function () {
2121
assert.throws(cookie.serialize.bind(cookie, 'foo\n', 'bar'), /argument name is invalid/)
2222
assert.throws(cookie.serialize.bind(cookie, 'foo\u280a', 'bar'), /argument name is invalid/)
23+
assert.throws(cookie.serialize.bind(cookie, 'foo bar', 'bar'), /argument name is invalid/)
2324
})
2425
})
2526

@@ -52,6 +53,9 @@ describe('cookie.serialize(name, value, options)', function () {
5253
assert.throws(cookie.serialize.bind(cookie, 'foo', '+ \n', {
5354
encode: function (v) { return v }
5455
}), /argument val is invalid/)
56+
assert.throws(cookie.serialize.bind(cookie, 'foo', 'foo bar', {
57+
encode: function (v) { return v }
58+
}), /argument val is invalid/)
5559
})
5660
})
5761

0 commit comments

Comments
 (0)
Please sign in to comment.