Skip to content

Commit

Permalink
fix: ReDOS in isEmail and isHSL (#1651)
Browse files Browse the repository at this point in the history
* chore: bump mocha version to fix npm audit warning

* fix(isHSL): update hslComma regex to prevent ReDOS

* fix(isEmail): update splitNameAddress regex to prevent ReDOS

* chore: rollback mocha version to allow testing on node 8 and 6

* fix(isHSL): remove unnecessary use of let

closes #1597 #1598
  • Loading branch information
tux-tn committed Apr 20, 2021
1 parent 2a3a1c3 commit b986f3d
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -45,7 +45,7 @@
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.11.0",
"mocha": "^5.1.1",
"mocha": "^6.2.3",
"nyc": "^14.1.0",
"rimraf": "^3.0.0",
"rollup": "^0.43.0",
Expand Down
16 changes: 9 additions & 7 deletions src/lib/isEmail.js
Expand Up @@ -16,7 +16,7 @@ const default_email_options = {

/* eslint-disable max-len */
/* eslint-disable no-control-regex */
const splitNameAddress = /^([^\x00-\x1F\x7F-\x9F\cX]+)<(.+)>$/i;
const splitNameAddress = /^([^\x00-\x1F\x7F-\x9F\cX]+)</i;
const emailUserPart = /^[a-z\d!#\$%&'\*\+\-\/=\?\^_`{\|}~]+$/i;
const gmailUserPart = /^[a-z\d]+$/;
const quotedEmailUser = /^([\s\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e]|(\\[\x01-\x09\x0b\x0c\x0d-\x7f]))*$/i;
Expand All @@ -31,9 +31,7 @@ const defaultMaxEmailLength = 254;
* @param {String} display_name
*/
function validateDisplayName(display_name) {
const trim_quotes = display_name.match(/^"(.+)"$/i);
const display_name_without_quotes = trim_quotes ? trim_quotes[1] : display_name;

const display_name_without_quotes = display_name.replace(/^"(.+)"$/, '$1');
// display name with only spaces is not valid
if (!display_name_without_quotes.trim()) {
return false;
Expand All @@ -44,7 +42,7 @@ function validateDisplayName(display_name) {
if (contains_illegal) {
// if contains illegal characters,
// must to be enclosed in double-quotes, otherwise it's not a valid display name
if (!trim_quotes) {
if (display_name_without_quotes === display_name) {
return false;
}

Expand All @@ -67,8 +65,12 @@ export default function isEmail(str, options) {
if (options.require_display_name || options.allow_display_name) {
const display_email = str.match(splitNameAddress);
if (display_email) {
let display_name;
[, display_name, str] = display_email;
let display_name = display_email[1];

// Remove display name and angle brackets to get email address
// Can be done in the regex but will introduce a ReDOS (See #1597 for more info)
str = str.replace(display_name, '').replace(/(^<|>$)/g, '');

// sometimes need to trim the last space to get the display name
// because there may be a space between display name and email address
// eg. myname <address@gmail.com>
Expand Down
15 changes: 12 additions & 3 deletions src/lib/isHSL.js
@@ -1,10 +1,19 @@
import assertString from './util/assertString';


const hslcomma = /^(hsl)a?\(\s*((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?))(deg|grad|rad|turn|\s*)(\s*,\s*(\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%){2}\s*(,\s*((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%?)\s*)?\)$/i;
const hslspace = /^(hsl)a?\(\s*((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?))(deg|grad|rad|turn|\s)(\s*(\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%){2}\s*(\/\s*((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%?)\s*)?\)$/i;
const hslComma = /^hsla?\(((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?))(deg|grad|rad|turn)?(,(\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%){2}(,((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%?))?\)$/i;
const hslSpace = /^hsla?\(((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?))(deg|grad|rad|turn)?(\s(\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%){2}\s?(\/\s((\+|\-)?([0-9]+(\.[0-9]+)?(e(\+|\-)?[0-9]+)?|\.[0-9]+(e(\+|\-)?[0-9]+)?)%?)\s?)?\)$/i;


export default function isHSL(str) {
assertString(str);
return hslcomma.test(str) || hslspace.test(str);

// Strip duplicate spaces before calling the validation regex (See #1598 for more info)
const strippedStr = str.replace(/\s+/g, ' ').replace(/\s?(hsla?\(|\)|,)\s?/ig, '$1');

if (strippedStr.indexOf(',') !== -1) {
return hslComma.test(strippedStr);
}

return hslSpace.test(strippedStr);
}

0 comments on commit b986f3d

Please sign in to comment.