diff --git a/README.md b/README.md index e92e18f0..87788338 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,9 @@ Cookies.remove('name', { path: '' }); (From [Internet Explorer Cookie Internals (FAQ)](http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx)) -This means one cannot set a path using `path: window.location.pathname` in case such pathname contains a filename like so: `/check.html` (or at least, such cookie cannot be read correctly). +This means one cannot set a path using `window.location.pathname` in case such pathname contains a filename like so: `/check.html` (or at least, such cookie cannot be read correctly). + +In fact, you should never allow untrusted input to set the cookie attributes or you might be exposed to a [XSS attack](https://github.com/js-cookie/js-cookie/issues/396). ### domain diff --git a/src/js.cookie.js b/src/js.cookie.js index 9a0945ed..86cc600c 100644 --- a/src/js.cookie.js +++ b/src/js.cookie.js @@ -87,7 +87,15 @@ if (attributes[attributeName] === true) { continue; } - stringifiedAttributes += '=' + attributes[attributeName]; + + // Considers RFC 6265 section 5.2: + // ... + // 3. If the remaining unparsed-attributes contains a %x3B (";") + // character: + // Consume the characters of the unparsed-attributes up to, + // not including, the first %x3B (";") character. + // ... + stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; } return (document.cookie = key + '=' + value + stringifiedAttributes); } diff --git a/test/tests.js b/test/tests.js index 85ab57fb..00f6c369 100644 --- a/test/tests.js +++ b/test/tests.js @@ -294,6 +294,16 @@ QUnit.test('undefined attribute value', function (assert) { }), 'c=v; path=/', 'should not write undefined unofficial attribute'); }); +// github.com/js-cookie/js-cookie/issues/396 +QUnit.test('sanitization of attributes to prevent XSS from untrusted input', function (assert) { + assert.expect(1); + assert.strictEqual(Cookies.set('c', 'v', { + path: '/;domain=sub.domain.com', + domain: 'site.com;remove_this', + customAttribute: 'value;;remove_this' + }), 'c=v; path=/; domain=site.com; customAttribute=value', 'should not allow semicolon in a cookie attribute'); +}); + QUnit.module('remove', lifecycle); QUnit.test('deletion', function (assert) {