CVE-2014-6394 (published 2014-10-08T17:55Z)

visionmedia send before 0.8.4 for Node.js uses a partial comparison for verifying whether a directory is within the document root, which allows remote attackers to access restricted directories, as demonstrated using "public-restricted" under a "public" directory.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: CWE-22
cwe_name: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
extended_description: 
            Many file operations are intended to take place within a restricted directory. By using special elements such as ".." and "/" separators, attackers can escape outside of the restricted location to access files or directories that are elsewhere on the system. One of the most common special elements is the "../" sequence, which in most modern operating systems is interpreted as the parent directory of the current location. This is referred to as relative path traversal. Path traversal also covers the use of absolute pathnames such as "/usr/local/bin" to access unexpected files. This is referred to as absolute path traversal.
         
         

Fix information:
repo_url: https://github.com/visionmedia/send
commit_details: repo_url: https://github.com/visionmedia/send
author: Douglas Christopher Wilson
author_date: 2014-09-04 14:27:58-04:00
msg: Fix a path traversal issue when using root

fixes #59
fixes #60
repository: repo_url: https://github.com/visionmedia/send
repo_name: pillarjs/send
description: Streaming static file server with Range and conditional-GET support
repo_language: JavaScript
owner: visionmedia
file_changes: filename: History.md
change_type: ModificationType.MODIFY
diff: @@ -1,3 +1,8 @@
+unreleased
+==========
+
+  * Fix a path traversal issue when using `root`
+
 0.8.3 / 2014-08-16
 ==================
 

programming_language: Markdown
filename: send.js
change_type: ModificationType.MODIFY
diff: @@ -412,7 +412,7 @@ SendStream.prototype.pipe = function(res){
   if (root !== null) {
     // join / normalize from optional root dir
     path = normalize(join(root, path))
-    root = normalize(root)
+    root = normalize(root + sep)
 
     // malicious path
     if (path.substr(0, root.length) !== root) {
@@ -421,7 +421,7 @@ SendStream.prototype.pipe = function(res){
     }
 
     // explode path parts
-    parts = path.substr(root.length + 1).split(sep)
+    parts = path.substr(root.length).split(sep)
   } else {
     // ".." is malicious without "root"
     if (upPathRegexp.test(path)) {

programming_language: JavaScript
filename: name.txt
change_type: ModificationType.ADD
diff: @@ -0,0 +1 @@
+loki
\ No newline at end of file

programming_language: Batchfile
filename: send.js
change_type: ModificationType.MODIFY
diff: @@ -1097,6 +1097,17 @@ describe('send(file, options)', function(){
         .expect(200, 'tobi', done)
       })
 
+      it('should with with trailing slash', function(done){
+        var app = http.createServer(function(req, res){
+          send(req, req.url, {root: __dirname + '/fixtures/'})
+          .pipe(res);
+        });
+
+        request(app)
+        .get('/name.txt')
+        .expect(200, 'tobi', done)
+      })
+
       it('should restrict paths to within root', function(done){
         var app = http.createServer(function(req, res){
           send(req, req.url, {root: __dirname + '/fixtures'})
@@ -1118,6 +1129,17 @@ describe('send(file, options)', function(){
         .get('/pets/../../send.js')
         .expect(403, done)
       })
+
+      it('should not allow root transversal', function(done){
+        var app = http.createServer(function(req, res){
+          send(req, req.url, {root: __dirname + '/fixtures/name.d'})
+          .pipe(res);
+        });
+
+        request(app)
+        .get('/../name.dir/name.txt')
+        .expect(403, done)
+      })
     })
 
     describe('when missing', function(){

programming_language: JavaScript