Skip to content

Commit 684d088

Browse files
committed
test(serialize): additional tests for proper name, domain and path RFC validations
These tests are to help illustrate vulnerabilities in the cookie name, domain and path strings. The lack of filtering delimiters like semicolon and comma is the major concern but other characters can present security problems as well. [PR jshttp#167][1] fixes these vulnerabilities and tests should pass with those new validations added. [1]: jshttp#167
1 parent 38323ba commit 684d088

File tree

1 file changed

+125
-15
lines changed

1 file changed

+125
-15
lines changed

test/serialize.js

Lines changed: 125 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,98 @@ describe('cookie.serialize(name, value)', function () {
1717
assert.equal(cookie.serialize('foo', ''), 'foo=')
1818
})
1919

20+
it('should serialize valid name', function () {
21+
const validNames = [
22+
'foo',
23+
'foo!bar',
24+
'foo#bar',
25+
'foo$bar',
26+
`foo'bar`,
27+
'foo*bar',
28+
'foo+bar',
29+
'foo-bar',
30+
'foo.bar',
31+
'foo^bar',
32+
'foo_bar',
33+
'foo`bar',
34+
'foo|bar',
35+
'foo~bar',
36+
'foo7bar',
37+
];
38+
39+
validNames.forEach((name) => {
40+
assert.equal(cookie.serialize(name, 'baz'), `${name}=baz`, `Expected serialized value for name: "${name}"`);
41+
});
42+
});
43+
2044
it('should throw for invalid name', function () {
21-
assert.throws(cookie.serialize.bind(cookie, 'foo\n', 'bar'), /argument name is invalid/)
22-
assert.throws(cookie.serialize.bind(cookie, 'foo\u280a', 'bar'), /argument name is invalid/)
23-
})
45+
const invalidNames = [
46+
'foo\n',
47+
'foo\u280a',
48+
'foo/foo',
49+
'foo,foo',
50+
'foo;foo',
51+
'foo@foo',
52+
'foo[foo]',
53+
'foo?foo',
54+
'foo:foo',
55+
'foo!foo',
56+
'foo{foo}',
57+
'foo foo',
58+
'foo\tfoo',
59+
'foo"foo',
60+
'foo<script>foo'
61+
];
62+
63+
invalidNames.forEach((name) => {
64+
assert.throws(
65+
cookie.serialize.bind(cookie, name, 'bar'),
66+
/argument name is invalid/,
67+
`Expected an error for invalid name: "${name}"`
68+
);
69+
});
70+
});
2471
})
2572

2673
describe('cookie.serialize(name, value, options)', function () {
2774
describe('with "domain" option', function () {
28-
it('should serialize domain', function () {
29-
assert.equal(cookie.serialize('foo', 'bar', { domain: 'example.com' }),
30-
'foo=bar; Domain=example.com')
31-
})
75+
76+
it('should serialize valid domain', function () {
77+
const validDomains = [
78+
'example.com',
79+
'sub.example.com',
80+
'my-site.org',
81+
'localhost'
82+
];
83+
84+
validDomains.forEach((domain) => {
85+
assert.equal(
86+
cookie.serialize('foo', 'bar', { domain }),
87+
`foo=bar; Domain=${domain}`,
88+
`Expected serialized value for domain: "${domain}"`
89+
);
90+
});
91+
});
3292

3393
it('should throw for invalid value', function () {
34-
assert.throws(cookie.serialize.bind(cookie, 'foo', 'bar', { domain: 'example.com\n' }),
35-
/option domain is invalid/)
36-
})
94+
const invalidDomains = [
95+
'example.com\n',
96+
'sub.example.com\u0000',
97+
'my site.org',
98+
'domain..com',
99+
'.example.com',
100+
'example.com; Path=/',
101+
'example.com /* inject a comment */'
102+
];
103+
104+
invalidDomains.forEach((domain) => {
105+
assert.throws(
106+
cookie.serialize.bind(cookie, 'foo', 'bar', { domain }),
107+
/option domain is invalid/,
108+
`Expected an error for invalid domain: "${domain}"`
109+
);
110+
});
111+
});
37112
})
38113

39114
describe('with "encode" option', function () {
@@ -128,14 +203,49 @@ describe('cookie.serialize(name, value, options)', function () {
128203
})
129204

130205
describe('with "path" option', function () {
206+
131207
it('should serialize path', function () {
132-
assert.equal(cookie.serialize('foo', 'bar', { path: '/' }), 'foo=bar; Path=/')
133-
})
208+
const validPaths = [
209+
'/',
210+
'/login',
211+
'/foo.bar/baz',
212+
'/foo-bar',
213+
'/foo=bar?baz',
214+
'/foo"bar"',
215+
'/../foo/bar',
216+
'../foo/',
217+
'./'
218+
];
219+
220+
validPaths.forEach((path) => {
221+
assert.equal(
222+
cookie.serialize('foo', 'bar', { path }),
223+
`foo=bar; Path=${path}`,
224+
`Expected serialized value for path: "${path}"`
225+
);
226+
});
227+
});
134228

135229
it('should throw for invalid value', function () {
136-
assert.throws(cookie.serialize.bind(cookie, 'foo', 'bar', { path: '/\n' }),
137-
/option path is invalid/)
138-
})
230+
const invalidPaths = [
231+
'/\n',
232+
'/foo\u0000',
233+
'/foo bar',
234+
'/path/with\rnewline',
235+
'/path\\with\\backslash',
236+
'/; Path=/sensitive-data',
237+
'/login"><script>alert(1)</script>'
238+
];
239+
240+
invalidPaths.forEach((path) => {
241+
assert.throws(
242+
cookie.serialize.bind(cookie, 'foo', 'bar', { path }),
243+
/option path is invalid/,
244+
`Expected an error for invalid path: "${path}"`
245+
);
246+
});
247+
});
248+
139249
})
140250

141251
describe('with "priority" option', function () {

0 commit comments

Comments
 (0)