Last tested: 24 Jul, 2018
sequelize (latest)
Published 22 Jul, 2018
No known vulnerabilities in sequelize
Security wise, sequelize seems to be a safe package to use.
Over time, new vulnerabilities may be disclosed on sequelize and other packages. To easily find, fix and prevent such vulnerabilties, protect your repos with Snyk!
Vulnerable versions of sequelize
Fixed in 4.17.2
Regular Expression Denial of Service (ReDoS)
Detailed paths
- Introduced through: sequelize@4.17.1 > validator@8.2.0
Overview
validator
is a library of string validators and sanitizers.
Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) attacks. It used a regular expression (^\s*data:([a-z]+\/[a-z0-9\-\+]+(;[a-z\-]+=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9!\$&',\(\)\*\+,;=\-\._~:@\/\?%\s]*\s*$
) in order to validate Data URIs. This can cause an impact of about 10 seconds matching time for data 70K characters long.
Disclosure Timeline
- Feb 15th, 2018 - Initial Disclosure to package owner
- Feb 16th, 2018 - Initial Response from package owner
- Feb 18th, 2018 - Fix issued
- Feb 18th, 2018 - Vulnerability published
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
Remediation
Upgrade validator
to version 9.4.1 or higher.
References
Fixed in 4.1.0
Prototype Pollution
Detailed paths
- Introduced through: sequelize@4.0.0-2 > lodash@4.15.0
Overview
lodash is a javaScript utility library delivering modularity, performance & extras.
Affected versions of this package are vulnerable to Prototype Pollution.
The utilities function allow modification of the Object
prototype. If an attacker can control part of the structure passed to this function, they could add or modify an existing property.
PoC by Olivier Arteau (HoLyVieR)
var _= require('lodash');
var malicious_payload = '{"__proto__":{"oops":"It works !"}}';
var a = {};
console.log("Before : " + a.oops);
_.merge({}, JSON.parse(malicious_payload));
console.log("After : " + a.oops);
Remediation
Upgrade lodash
to version 4.17.5 or higher.
References
Fixed in 3.23.6
SQL Injection via GeoJSON
Detailed paths
- Introduced through: sequelize@3.23.5
Overview
sequelize
versions prior to 3.23.6
are vulnerable to SQL injection via GeoJSON documents that contain a value with a single quote. GeoJSON is a format used for encoding a variety of geographic data structures in a standard JSON document. The vulnerability exists within GeoJSON documents using the function
ST_GeomFromGeoJSON
(for postgresql/postgis) and the function GeomFromText
(for mysql).
Note that sequelize
users who do not use these specific functions are not affected. For users who do use these functions, this vulnerability has a high impact and is easily expoited, hence its high severity classification.
Remediation
Upgrade to version 3.23.6 or greater.
References
Fixed in 3.23.2
Buffer Overflow
Detailed paths
- Introduced through: sequelize@3.23.1 > validator@4.9.0
Overview
validator
is a library of string validators and sanitizers.
Affected versions of this package are vulnerable to Buffer Overflow. It used a regular expression (/^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i
) in order to validate Base64 strings.
Remediation
Upgrade validator
to version 5.0.0 or higher.
References
Fixed in 3.20.0
SQL Injection in IN statement
Detailed paths
- Introduced through: sequelize@3.19.3
Overview
sequelize
versions prior to 3.20.0 improperly escape arrays of strings bound to named parameters.
Remediation
Upgrade to version 3.20.0 or greater.
References
Fixed in 3.17.2
Remote Memory Exposure
Detailed paths
- Introduced through: sequelize@3.17.1
Overview
A potential memory disclosure vulnerability exists in sequelize versions prior to 3.17.2.
A field of type DataTypes.BLOB
can be used to expose sensitive information such as code, runtime memory and user data into the database.
Details
sequelize
uses the Buffer
type to represent DataTypes.BLOB
.
Initializing a Buffer
with integer N
creates a Buffer
of length N
with non zero-ed out memory.
Example:
var x = new Buffer(100); // uninitialized Buffer of length 100
// vs
var x = new Buffer('100'); // initialized Buffer with value of '100'
Initializing a BLOB
field in such manner will dump uninitialized
memory into the database.
The patch wraps Buffer
field initialization in sequelize by converting a
number
value N
to a string, initializing the Buffer
with N
in its
ascii form.
Proof of concept
var Sequelize = require('sequelize');
var sequelize = new Sequelize('pastebin', null, null,
{ host: '127.0.0.1', dialect: 'postgres', });
var Task = sequelize.define('Pastebin', {
title: Sequelize.STRING,
content: Sequelize.BLOB,
});
Task.create({
title: 'title',
content: 100,
}).then(function (task) {
console.log(task.title);
console.log(task.content); // will print out 100 bytes of previously used memory
});
Remediation
Upgrade sequelize
to version >= 3.17.3
References
- https://github.com/sequelize/sequelize/blob/master/changelog.md#3172
- https://github.com/sequelize/sequelize/commit/cbfaa4f0a135cfc55874c9bfc39ead2d85c417e9
- https://github.com/ChALkeR/notes/blob/master/Lets-fix-Buffer-API.md#previous-materials
- https://github.com/ChALkeR/notes/blob/master/Buffer-knows-everything.md
Fixed in 3.17.0
SQL Injection in order/limit
Detailed paths
- Introduced through: sequelize@3.16.0
Overview
sequelize
versions prior to 3.17.0 are vulnerable to SQL Injection attacks if untrusted user input is passed into the order
or limit
parameters.
Example
models.User.findAll({
limit: '1; DELETE FROM "Users" WHERE 1=1; --',
}).then(function (users) {
console.log(users);
});
Remediation
Upgrade to version 3.17.0 or greater.
References
Fixed in 3.12.1
SQL Injection
Detailed paths
- Introduced through: sequelize@3.12.0
Overview
sequelize
is a multi dialect ORM for Node.JS/io.js.
Affected versions of the package are vulnerable to SQL Injection via the user search by typing the name they want to search for and the application then executes:
User.findAll( { where: { name: req.body.name } } )
a malicious attacker may exploit this to find the users password by entering $password$
. This could be avoided by specifying the exact column to search: the user column.
Remediation
Upgrade sequelize
to version 3.12.1 or higher.
References
Fixed in 3.0.0
SQL Injection
Detailed paths
- Introduced through: sequelize@2.1.3
Overview
Beginning with sequelize
version 3.0.0, two security related changes were introduced:
findOne
no longer takes a string / integer / binary argument to represent a primaryKey. UsefindById
instead.where: "raw query"
is no longer legal, you must now explicitly usewhere: ["raw query", [replacements]]
Remediation
Upgrade to version 3.0.0 or greater.
References
Fixed in 2.0.6
Cross-site Scripting (XSS)
Detailed paths
- Introduced through: sequelize@2.0.5 > validator@3.22.2
Overview
validator
is a library of string validators and sanitizers.
Affected versions of this package are vulnerable to Cross-site Scripting (XSS) in IE9 due to unescaped backticks.
Details
Cross-Site Scripting (XSS) attacks occur when an attacker tricks a user’s browser to execute malicious JavaScript code in the context of a victim’s domain. Such scripts can steal the user’s session cookies for the domain, scrape or modify its content, and perform or modify actions on the user’s behalf, actions typically blocked by the browser’s Same Origin Policy.
These attacks are possible by escaping the context of the web application and injecting malicious scripts in an otherwise trusted website. These scripts can introduce additional attributes (say, a "new" option in a dropdown list or a new link to a malicious site) and can potentially execute code on the clients side, unbeknown to the victim. This occurs when characters like \< > \" \' are not escaped properly.
There are a few types of XSS:
- Persistent XSS is an attack in which the malicious code persists into the web app’s database.
- Reflected XSS is an which the website echoes back a portion of the request. The attacker needs to trick the user into clicking a malicious link (for instance through a phishing email or malicious JS on another page), which triggers the XSS attack.
- DOM-based XSS is an that occurs purely in the browser when client-side JavaScript echoes back a portion of the URL onto the page. DOM-Based XSS is notoriously hard to detect, as the server never gets a chance to see the attack taking place.
Remediation
Upgrade validator
to version 3.35.0 or higher.
References
Fixed in 2.0.1
Regular Expression Denial of Service (ReDoS)
Detailed paths
- Introduced through: sequelize@2.0.0-rc8 > moment@2.8.4
Overview
moment
is a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
Affected versions of the package are vulnerable to Regular Expression Denial of Service (ReDoS) attacks for any locale that has separate format and standalone options and format
input can be controlled by the user.
An attacker can provide a specially crafted input to the format
function, which nearly matches the pattern being matched. This will cause the regular expression matching to take a long time, all the while occupying the event loop and preventing it from processing other requests and making the server unavailable (a Denial of Service attack).
Disclosure Timeline
- October 19th, 2016 - Reported the issue to package owner.
- October 19th, 2016 - Issue acknowledged by package owner.
- October 24th, 2016 - Issue fixed and version
2.15.2
released.
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
References
Regular Expression Denial of Service (ReDoS)
Detailed paths
- Introduced through: sequelize@2.0.0-rc8 > moment@2.8.4
Overview
moment
is a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
An attacker can provide a long value to the duration
function, which nearly matches the pattern being matched. This will cause the regular expression matching to take a long time, all the while occupying the event loop and preventing it from processing other requests and making the server unavailable (a Denial of Service attack).
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
Remediation
Upgrade moment
to version 2.11.2
or greater.
References
Regular Expression Denial of Service (ReDoS)
Detailed paths
- Introduced through: sequelize@2.0.0-rc8 > moment@2.8.4
Overview
moment
is a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
Affected versions of this package are vulnerable to Regular expression Denial of Service (ReDoS) attacks. It used a regular expression (/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i
) in order to parse dates specified as strings. This can cause a very low impact of about 2 seconds matching time for data 50k characters long.
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
Remediation
Upgrade moment
to version 2.19.3
or higher.
References
Fixed in 2.0.0-rc8
SQL Injection in Order
Detailed paths
- Introduced through: sequelize@2.0.0-rc7
Overview
sequelize
versions prior to 2.0.0-rc7 are vulnerable to SQL Injection attacks if untrusted user input is passed into the order
parameter.
Remediation
Upgrade to version 2.0.0-rc8 or greater.
References
Fixed in 2.0.0-rc3
SQL Injection
Detailed paths
- Introduced through: sequelize@2.0.0-rc2 > sql@0.39.0
Overview
sql is a sql string builder for node - supports PostgreSQL, mysql, Microsoft SQL Server, Oracle and sqlite dialects.
Affected versions of this package are vulnerable to SQL Injection. A malicious user may insert potentially user-controlled content into the queries without proper escaping, in cases where that is not verified additionally in the applications that are using sql library.
Remediation
There is no fix version for sql
.
References
Regular Expression Denial of Service (DoS)
Detailed paths
- Introduced through: sequelize@2.0.0-rc2 > validator@3.16.1
Overview
validator
is a library of string validators and sanitizers.
Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) attacks. It used a regular expression in order to validate URLs.
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
Remediation
Update to version 3.22.1 or greater.
References
Fixed in 2.0.0-dev13
Regular Expression Denial of Service (ReDoS)
Detailed paths
- Introduced through: sequelize@2.0.0-dev12 > underscore.string@2.3.3
Overview
underscore.string is a String manipulation helpers for javascript.
Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS). It parses dates using regex strings, which may cause a slowdown of 2 seconds per 50k characters.
Details
Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.
The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.
Let’s take the following regular expression as an example:
regex = /A(B|C+)+D/
This regular expression accomplishes the following:
A
The string must start with the letter 'A'(B|C+)+
The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the+
matches one or more times). The+
at the end of this section states that we can look for one or more matches of this section.D
Finally, we ensure this section of the string ends with a 'D'
The expression would match inputs such as ABBD
, ABCCCCD
, ABCBCCCD
and ACCCCCD
It most cases, it doesn't take very long for a regex engine to find a match:
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
1.79s user 0.02s system 99% cpu 1.812 total
The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.
Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.
Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:
- CCC
- CC+C
- C+CC
- C+C+C.
The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.
From there, the number of steps the engine must use to validate a string just continues to grow.
String | Number of C's | Number of steps |
---|---|---|
ACCCX | 3 | 38 |
ACCCCX | 4 | 71 |
ACCCCCX | 5 | 136 |
ACCCCCCCCCCCCCCX | 14 | 65,553 |
By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.
Remediation
There is no fix version for underscore.string
.
References
Fixed in 2.0.0-dev7
Cross-site Scripting (XSS)
Detailed paths
- Introduced through: sequelize@2.0.0-dev6 > validator@1.5.1
Overview
validator is a module for Node.js contains functionality meant to filter potential XSS attacks (a filter called xss). A method of bypassing the filter via an encoded URL has been publicly disclosed. In general, because the function’s filtering is blacklist-based it is likely that other bypasses will be discovered in the future. Developers are encouraged not to use the xss filter function in this package. The xss() function removes the word "javascript" when contained inside an attribute. However, it does not properly handle cases where characters have been hex-encoded. As a result, it is possible to build an input that bypasses the filter but which the browser will accept as valid JavaScript.
For example, browsers interpret abc as abc.
Details
Cross-Site Scripting (XSS) attacks occur when an attacker tricks a user’s browser to execute malicious JavaScript code in the context of a victim’s domain. Such scripts can steal the user’s session cookies for the domain, scrape or modify its content, and perform or modify actions on the user’s behalf, actions typically blocked by the browser’s Same Origin Policy.
These attacks are possible by escaping the context of the web application and injecting malicious scripts in an otherwise trusted website. These scripts can introduce additional attributes (say, a "new" option in a dropdown list or a new link to a malicious site) and can potentially execute code on the clients side, unbeknown to the victim. This occurs when characters like \< > \" \' are not escaped properly.
There are a few types of XSS:
- Persistent XSS is an attack in which the malicious code persists into the web app’s database.
- Reflected XSS is an which the website echoes back a portion of the request. The attacker needs to trick the user into clicking a malicious link (for instance through a phishing email or malicious JS on another page), which triggers the XSS attack.
- DOM-based XSS is an that occurs purely in the browser when client-side JavaScript echoes back a portion of the URL onto the page. DOM-Based XSS is notoriously hard to detect, as the server never gets a chance to see the attack taking place.
Remediation
Upgrade to the latest version of this library. However, it should be noted that the fix for this vulnerability was to remove the xss filter functionality. Seek another library to provide proper output encoding.
References
Fixed in 1.7.0-alpha3
SQL Injection
Detailed paths
- Introduced through: sequelize@1.7.0-alpha2
Overview
sequelize
versions prior to 1.7.0-alpha3 are vulnerable to SQL Injection attacks if untrusted user input is passed into the order
parameter.
Remediation
Upgrade to version 1.7.0-alpha3 or greater.
References
Fixed in 1.7.0-alpha2
Cross-site Scripting (XSS)
Detailed paths
- Introduced through: sequelize@1.7.0-alpha1 > validator@0.4.28
Overview
The validator module for Node.js contains functionality meant to filter potential XSS attacks (a filter called xss). Several ways to bypass the filter were discovered. In general, because the function’s filtering is blacklist-based it is likely that other bypasses will be discovered in the future. Developers are encouraged not to use the xss filter function in this package.
Source: Node Security Project
Details
Various inputs that could bypass the filter were discovered:
Improper parsing of nested tags:
<s <onmouseover="alert(1)"> <;s onmouseover="alert(1)">This is a test</s>
Incomplete filtering of javascript: URIs:
<a href="javascriptJ a V a S c R iPt::alert(1)" "<s>">test</a>
UI Redressing:
<div style="z-index: 9999999; background-color: green; width: 100%; height: 100%">
<h1>You have won</h1>Please click the link and enter your login details:
<a href="http://example.com/">http://good.com</a>
</div>
Bypass via Nested Forbidden Strings:
<scrRedirecRedirect 302t 302ipt type="text/javascript">prompt(1);</scrRedirecRedirect 302t 302ipt>
Additional bypasses were discovered by Krzysztof Kotowicz in 2012 when auditing CodeIgniter's XSS filtering function, which this code was based off of.
Details
Cross-Site Scripting (XSS) attacks occur when an attacker tricks a user’s browser to execute malicious JavaScript code in the context of a victim’s domain. Such scripts can steal the user’s session cookies for the domain, scrape or modify its content, and perform or modify actions on the user’s behalf, actions typically blocked by the browser’s Same Origin Policy.
These attacks are possible by escaping the context of the web application and injecting malicious scripts in an otherwise trusted website. These scripts can introduce additional attributes (say, a "new" option in a dropdown list or a new link to a malicious site) and can potentially execute code on the clients side, unbeknown to the victim. This occurs when characters like \< > \" \' are not escaped properly.
There are a few types of XSS:
- Persistent XSS is an attack in which the malicious code persists into the web app’s database.
- Reflected XSS is an which the website echoes back a portion of the request. The attacker needs to trick the user into clicking a malicious link (for instance through a phishing email or malicious JS on another page), which triggers the XSS attack.
- DOM-based XSS is an that occurs purely in the browser when client-side JavaScript echoes back a portion of the URL onto the page. DOM-Based XSS is notoriously hard to detect, as the server never gets a chance to see the attack taking place.
Remediation
If you are a developer currently using the xss filter function from the validator package, you should consider replacing it with the escape filter function from the same package. This function replaces all instances of angle brackets (<, >), ampersands, and quotation marks, so no HTML tags will be processed.
References
Fixed in 1.7.0
Uninitialized Memory Exposure
Detailed paths
- Introduced through: sequelize@1.6.0-beta-3 > mysql@2.0.1
Overview
mysql
is a node.js driver for mysql.
Affected versions of the package are vulnerable due to the unsafe use of the Buffer()
method. Uninitialized memory may be exposed when a value of type number
is provided to various methods in mysql
which require allocation of buffers and results in concatenation of uninitialized memory to the buffer collection.
This vulnerability is unlikely to be exploited, but may be possible if a server-side mysql
accepts typed input for passwords from the client even though the user doesn’t control the server-side code (i.e through JSON format).
Details
Constructing a Buffer
class with integer N
creates a Buffer
of length N
with raw (not "zero-ed") memory.
In the following example, the first call would allocate 100 bytes of memory, while the second example will allocate the memory needed for the string "100":
// uninitialized Buffer of length 100
x = new Buffer(100);
// initialized Buffer with value of '100'
x = new Buffer('100');
You can read more about the insecure Buffer
behavior on our blog.
Similar vulnerabilities were discovered in request, mongoose, ws and sequelize.
Remediation
Upgrade mysql
to version 2.14.0 or higher.
Note This is vulnerable only for Node <=4
References
Unauthorized SSL Connection due to lack of cert authentication
Detailed paths
- Introduced through: sequelize@1.6.0-beta-3 > mysql@2.0.1
Overview
mysql
is a node.js driver for mysql.
Affected versions of this package do not validate that the remote server has a trusted SSL certificate or not, making it easier for attackers to gain access to the MySQL Server.
Remediation
Upgrade mysql
to version 2.3.0 or higher.