Patterns in Node Package Vulnerabilities
Chetan Karande
Slide 2
Slide 2 text
About Me
▪ Principal Engineer, DTCC
▪ Project Leader, OWASP NodeGoat Project
▪ Author
Slide 3
Slide 3 text
532 packages/day
Slide 4
Slide 4 text
~ 700,000 packages
Slide 5
Slide 5 text
88 Disclosures
Slide 6
Slide 6 text
603 Vulnerabilities
Slide 7
Slide 7 text
1,098 Advisories
Slide 8
Slide 8 text
No content
Slide 9
Slide 9 text
No content
Slide 10
Slide 10 text
No content
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
npm audit
Snyk CLI
Slide 14
Slide 14 text
“By seeking and blundering we learn.”
- Johann Wolfgang von Goethe
Slide 15
Slide 15 text
No content
Slide 16
Slide 16 text
1,084
+ 528
1,023 Unique Advisories
Slide 17
Slide 17 text
No content
Slide 18
Slide 18 text
Insecure Access to File System
Slide 19
Slide 19 text
Insecure Access to File System
Pattern #1 Directory Traversal
Slide 20
Slide 20 text
No content
Slide 21
Slide 21 text
Root Cause: An insecure dependency vulnerable to Directory Traversal
Slide 22
Slide 22 text
Root Cause behind Directory Traversal
Missing or insufficient user input validation for path traversal characters
before using it in a path to serve contents on the server.
Slide 23
Slide 23 text
Root Cause for Directory Traversal
Missing or insufficient user input validation for path traversal characters
before using it in a URL to serve contents on the server.
Examples:
• /
• ../
• %2f
• %2e%2e/
• %2e%2e%2f,
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
Preventing Directory Traversal
✓ If the path needs to be supplied from the user input, sanitize the input to
remove path traversal characters (./ and ../ as well as encoded variations)
Slide 26
Slide 26 text
Insecure Access to File System
Pattern #2 Symlink Attack
Slide 27
Slide 27 text
Symlink attack is like staying in a hotel and getting a really noisy neighbor...
Symlink Attack
Slide 28
Slide 28 text
Symlink Attack
A malicious user sharing the host, could exploit this vulnerability to corrupt or
destroy vital system or application files to which only the target application
has the access.
Slide 29
Slide 29 text
Root Cause for Symlink Attack
• An application sharing the host server with other external users.
• Using predictable file or folder names when writing to shared directories
Slide 30
Slide 30 text
Example: The package writing logs to the shared /tmp directory with a
predictable file name
Slide 31
Slide 31 text
ln –s
Slide 32
Slide 32 text
Preventing Symlink Attack
✓ Avoid using shared system folders.
Slide 33
Slide 33 text
Example: The package using /tmp to buffer command results before
returning values
Slide 34
Slide 34 text
Preventing Symlink Attack
✓ Avoid using shared system folders.
✓ If you have to use a shared folder for writing non-sensitive data, use crypto
module’s randomBytes method to generate random filenames.
Slide 35
Slide 35 text
Sensitive Data Exposure
Slide 36
Slide 36 text
“The more you leave out, the more you highlight what you leave in.”
- Henry Green
Slide 37
Slide 37 text
Sensitive Data Exposure
Pattern #1 Leaking Application Secrets
Slide 38
Slide 38 text
Root Causes for Leaking Application Secrets
Application-specific secrets appearing at insecure places such as as:
- code repositories,
- log files,
- client-side storage,
- URLs,
- application global namespace
Slide 39
Slide 39 text
Example: Leaking the SSL private key in the code repository
Slide 40
Slide 40 text
Example: URLs with authentication tokens appearing in the logs
Slide 41
Slide 41 text
Example: OAuth Bearer Token appearing in the browser local-storage
Slide 42
Slide 42 text
Preventing Application Secrets Leakage
✓ Securely store applications secrets in Hardware Security Module (HSM) or
Key Management Services.
Slide 43
Slide 43 text
Preventing Application Secrets Leakage
✓ Securely store applications secrets in Hardware Security Module (HSM) or
Key Management Services.
✓ Mask any sensitive data before it appears in the log files.
Slide 44
Slide 44 text
Preventing Application Secrets Leakage
✓ Securely store applications secrets in Hardware Security Module (HSM) or
Key Management Services
✓ Mask any sensitive data before it appears in the log files
✓ To reduce impact of a leak, use short-lived tokens.
Slide 45
Slide 45 text
Sensitive Data Exposure
Pattern #2 Predictable Secrets
(Insecure Randomness)
Slide 46
Slide 46 text
Root causes for Insecure Randomness
• Using Math.random() method is to generate random values in security-
sensitive context (random tokens, resource IDs, or UUIDs).
• Math.random() is cryptographically insecure. It can produce predictable
values.
Slide 47
Slide 47 text
Example: Using Math.random to generate UUID
Slide 48
Slide 48 text
Example: Using Math.random() to generate Socket IDs
Slide 49
Slide 49 text
Preventing Insecure Randomness
✓ Use crypto module to generate random numbers instead of Math.random()
Slide 50
Slide 50 text
Preventing Insecure Randomness
✓ Use crypto module to generate random numbers instead of Math.random()
Slide 51
Slide 51 text
Sensitive Data Exposure
Pattern #3 Predictable Secrets
(Non-constant Time Comparison)
Slide 52
Slide 52 text
Root causes for Non-constant Time Comparison
• Using fail-fast comparison logic to match user inputs against sensitive
values.
• JavaScript native string comparison operators (=== and ==) perform the
non-constant time fail-first string comparison .
Slide 53
Slide 53 text
Example: Using Fail Fast operators to compare csrf tokens
Slide 54
Slide 54 text
Example: Using a Fail Fast iterator to compare byte arrays
Slide 55
Slide 55 text
No content
Slide 56
Slide 56 text
Preventing Timing Attacks
✓ Use a constant-time comparison logic that takes the same amount of time
regardless of the input values.
Slide 57
Slide 57 text
Preventing Timing Attacks
✓ Use a constant-time comparison logic that takes the same amount of time
regardless of the input values.
Slide 58
Slide 58 text
Sensitive Data Exposure
Pattern #4 Remote Memory Exposure
Slide 59
Slide 59 text
Root Cause for Remote Memory Exposure
▪ Prior to Node.js 8, the Buffer constructor that takes a number as an
argument, generates a Buffer instance with uninitialized underlying memory.
Slide 60
Slide 60 text
▪ Prior to Node.js 8, the Buffer constructor that takes a number as an
argument, generates a Buffer instance with uninitialized underlying memory.
▪ The contents of a newly created Buffer remain unknown and might contain
sensitive data.
Root Cause for Remote Memory Exposure
Slide 61
Slide 61 text
Examples of Uninitialized Memory Exposure
Example: Using unsafe Buffer constructor
Slide 62
Slide 62 text
Example: Using unsafe Buffer constructor
Slide 63
Slide 63 text
Example: Using unsafe Buffer constructor
Slide 64
Slide 64 text
Preventing Remote Memory Exposure
✓ Use a safe method Buffer.alloc(size) to create a buffer that is initialized with
zeroes:
Slide 65
Slide 65 text
Sensitive Data Exposure
Pattern #5 Insecure Network Usage
Slide 66
Slide 66 text
Root Cause for Insecure Network Usage
▪ Using insecure HTTP protocol to download resources as part of install
scripts or at runtime.
Slide 67
Slide 67 text
Root Cause for Insecure Network Usage
▪ Using insecure HTTP protocol to download resources as part of install
scripts or at runtime.
Slide 68
Slide 68 text
Preventing Insecure Network Usage
✓ Download resources over secure HTTPS connection.
✓ Provide an option for users to download dependencies in advance and
specify the location path.
Slide 69
Slide 69 text
Denial of Service
Slide 70
Slide 70 text
Denial of Service
Pattern #1 Exhausting System Resources
Slide 71
Slide 71 text
Root Cause behind DoS by Exhausting System Resources
• Allocating unrestricted amount of system resources based on the size of a user
input.
Slide 72
Slide 72 text
Example: Exceeding V8’s maximum string size limit
Slide 73
Slide 73 text
Example: Exceeding V8’s maximum buffer size limit
Slide 74
Slide 74 text
Example: Unrestricted file uploads exhausting file-system space
Slide 75
Slide 75 text
Example: Instantiating large number of Objects based on a user input
(very large array index: foo[0][1000000000]=bar)
Slide 76
Slide 76 text
Preventing DoS by Exhausting System Resources
✓ Validate size of a user input before processing it
Slide 77
Slide 77 text
Denial of Service
Pattern #2: Keeping Event Loop Busy
Slide 78
Slide 78 text
Node is fast when the work associated with each client at any given time is "small".
- Node.js Docs
Slide 79
Slide 79 text
Examples of DoS By Keeping Event Loop Busy
• Running an execution loop whose iterations depend on the length of a user
input.
Slide 80
Slide 80 text
• Running an execution loop whose iterations depend on the length of a user
input.
• Using unsafe Regular Expressions
Examples of DoS By Keeping Event Loop Busy
Slide 81
Slide 81 text
Regular Expression Denial of Service (ReDoS)
▪ By default, regular expressions get executed in the main event loop thread
▪ Evil regex can take exponential execution time when applied to certain non-
matching inputs.
Denial of Service
Pattern #3 Crashing Event Loop By Unhandled
Exceptions
Slide 86
Slide 86 text
No content
Slide 87
Slide 87 text
Common Causes of Unhandled Exceptions
#1 Failing to Handle Invalid User Inputs
Slide 88
Slide 88 text
• Caused by failing to validate user inputs for unexpected value, type, or
shape before processing them
Slide 89
Slide 89 text
Unexpected Character
Example: Trailing \ in URL localhost:3000/index.html\
Slide 90
Slide 90 text
Unexpected Object Value
Example: Unexpected HTTP Header Value { 'accept-encoding': 'a;b' }
Slide 91
Slide 91 text
Unexpected Object Shape
Example: Type coercion via HTTP Request Parameters
Slide 92
Slide 92 text
▪ User input coercion via HTTP Request Parameters in qs, Express, Koa
// GET /search?conference=fluent
request.query.conference
//=> "fluent”
Slide 93
Slide 93 text
▪ User input coercion via HTTP Request Parameters in qs, Express, Koa
// GET /search?conference=fluent&conference=velocity
request.query.conference
//=> ["fluent”, “velocity”]
Slide 94
Slide 94 text
▪ User input coercion via HTTP Request Parameters in qs, Express, Koa
// GET /search?conference[]=fluent
request.query.conference
//=> ["fluent”]
Slide 95
Slide 95 text
▪ User input coercion via HTTP Request Parameters in qs, Express, Koa
// GET /search?conference[fluent][year]=2018
request.query.conference
//=>
Slide 96
Slide 96 text
▪ User input coercion via HTTP Request Parameters in qs, Express, Koa
// GET /search?conference[fluent][year]=2018
request.query.conference
//=> {fluent: { year: '2018' }}
Slide 97
Slide 97 text
✓ Validate user inputs for expected values, type or shape before processing it.
(using joi package, for example)
Preventing Unhanded Exception Caused by Invalid User Input
Slide 98
Slide 98 text
Common Causes of Unhandled Exceptions
#2 Missing or Incorrect Operational Error Handling
Slide 99
Slide 99 text
Four mechanisms to communicate operational errors in Node.js:
1. throw new Error('something bad happened!');
Slide 100
Slide 100 text
Four mechanisms to communicate operational errors in Node.js:
1. throw new Error('something bad happened!');
1. callback(new Error('something bad happened!'));
Slide 101
Slide 101 text
Four mechanisms to communicate operational errors in Node.js:
1. throw new Error('something bad happened!');
1. callback(new Error('something bad happened!'));
1. return Promise.reject(new Error('something bad happened!'));
Slide 102
Slide 102 text
Four mechanisms to communicate operational errors in Node.js:
1. throw new Error('something bad happened!');
1. callback(new Error('something bad happened!'));
1. return Promise.reject(new Error('something bad happened!'));
1. myEmitter.emit('error', new Error(something bad
happened!'));
Slide 103
Slide 103 text
Example: Failure to handle error object passed in the callback
Slide 104
Slide 104 text
Preventing Unhanded Exception due to Operational Errors
✓ Be aware of the error delivery mechanism used by the invoked function and
handle errors accordingly.
Slide 105
Slide 105 text
Recap
▪ Insecure Access to File System
- Pattern #1 Directory Traversal
- Pattern #2 Symlink Attack