Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active June 4, 2025 17:36
Show Gist options
  • Save ryanflorence/701407 to your computer and use it in GitHub Desktop.
Save ryanflorence/701407 to your computer and use it in GitHub Desktop.
Node.JS static file web server. Put it in your path to fire up servers in any directory, takes an optional port argument.
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs")
port = process.argv[2] || 8888;
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
});
});
}).listen(parseInt(port, 10));
console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
@amejiarosario
Copy link

I created a new one that handles MIME types and uses ES6+

https://gist.github.com/amejiarosario/53afae82e18db30dadc9bc39035778e5

@kovid-rathee
Copy link

Got an error with path.exists, changed it to fs.exists and the snippet worked fine.

@duluca
Copy link

duluca commented Feb 28, 2017

@kovid-rathee I ran in to the same issue and your solution worked!

@Julia991
Copy link

Hey, guys what do you think about this article?
he best Node.js framework for your project: Express.js, Koa.js or Sails.js is express js the best framework for Node js?

@cmshiyas
Copy link

Awesome! I am new to Node.js and was trying to figure out how to configure this...This worked with a minor update as givne in another post creationix/howtonode.org#88
Thank you very much!

@robole
Copy link

robole commented Jun 26, 2017

ty. min req, what i was after

@dkebler
Copy link

dkebler commented Oct 31, 2017

path.exists has been deprecated. If you want a sync check then

  if (!fs.statSync(filename)) {
    response.writeHead(404, {'Content-Type': 'text/plain'})
    response.write('404 Not Found\n')
    response.end()
    return
  }

@dkebler
Copy link

dkebler commented Oct 31, 2017

even better how about the handler's fs stuff all async with callbacks

fs.stat(filename, function(err,stats) {
    if (err) {
      response.writeHead(404, {'Content-Type': 'text/plain'})
      response.write('404 Not Found\n')
      response.end()
      return
    }

    if (stats.isDirectory()) filename += '/index.html'

    fs.readFile(filename, 'binary', function(err, file) {
      if(err) {
        response.writeHead(500, {'Content-Type': 'text/plain'})
        response.write(err + '\n')
        response.end()
        return
      }
      response.writeHead(200)
      response.write(file, 'binary')
      response.end()
    })
  })

@Risyandi
Copy link

Thanks a lot :)

@mandaputtra
Copy link

Thanks a lot, but it can be hijacked

@XMB5
Copy link

XMB5 commented Jun 10, 2018

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

@Abd-Elrazek
Copy link

thanks ...it's great, that why I'm looking for it

@CCorb
Copy link

CCorb commented Feb 29, 2020

path.exists is now called fs.exists

@unsaved
Copy link

unsaved commented Mar 19, 2020

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

I guess you're not familiar with how path.join works, because as coded here it won't resolve to a directory outside of cwd directory branch.

@rpivo
Copy link

rpivo commented Apr 12, 2021

fs.exists is deprecated. fs.statSync can be used to check if file path exists, as in dkebler's code above.

@codespede
Copy link

Thank you for this!

@Anna-art125
Copy link

Incredible article, thanks for sharing it! I think this article will also be useful for you - Node js vs Python.

@JafarAkhondali
Copy link

I'm 15 years late to the party, but this is indeed insecure. PoC:
curl --path-as-is http://localhost:8888/../../../../../../../../etc/passwd

By default, when you send HTTP requests using curl, they'll be normalized. With --path-as-is flag you can prevent normalization, thus the exploit works. The same thing happens if you test the PoC in your browser. I think that's why most people didn't find the vulnerability.

This is insecure, someone can request /../../../etc/shadow or similar to read any file they want.

I guess you're not familiar with how path.join works, because as coded here it won't resolve to a directory outside of cwd directory branch.

No, I think you're not familiar with how path.join works, there is no mitigation for the directory boundary check here. We wrote a paper about this vulnerability as it spread almost EVERYWHERE.

You can test it in Node:
node -e 'console.log(path.join("/opt/app/www", "/../../../../etc/passwd")) // It will print /etc/passwd'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment