Skip to content

Commit 5fb988f

Browse files
brpvieiraZarel
authored andcommitted
Protect fs.stats from bad path arguments (cloudhead#223)
Prevents uncaught exception: TypeError [ERR_INVALID_ARG_VALUE]: The argument 'path' must be a string or Uint8Array without null bytes.
1 parent 83aac2e commit 5fb988f

2 files changed

Lines changed: 21 additions & 4 deletions

File tree

lib/node-static.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ const fs = require('fs')
1212
// Current version
1313
const version = [0, 7, 9];
1414

15+
function tryStat(p, callback) {
16+
try {
17+
fs.stat(p, callback);
18+
} catch (e) {
19+
callback(e);
20+
}
21+
}
22+
1523
const Server = function (root, options) {
1624
if (root && (typeof(root) === 'object')) { options = root; root = null }
1725

@@ -57,7 +65,7 @@ Server.prototype.serveDir = function (pathname, req, res, finish) {
5765
const htmlIndex = path.join(pathname, this.options.indexFile),
5866
that = this;
5967

60-
fs.stat(htmlIndex, function (e, stat) {
68+
tryStat(htmlIndex, function (e, stat) {
6169
if (!e) {
6270
const status = 200;
6371
const headers = {};
@@ -90,7 +98,7 @@ Server.prototype.serveFile = function (pathname, status, headers, req, res) {
9098

9199
pathname = this.resolve(pathname);
92100

93-
fs.stat(pathname, function (e, stat) {
101+
tryStat(pathname, function (e, stat) {
94102
if (e) {
95103
return promise.emit('error', e);
96104
}
@@ -145,7 +153,7 @@ Server.prototype.servePath = function (pathname, status, headers, req, res, fini
145153
// Make sure we're not trying to access a
146154
// file outside of the root.
147155
if (pathname.startsWith(that.root)) {
148-
fs.stat(pathname, function (e, stat) {
156+
tryStat(pathname, function (e, stat) {
149157
if (e) {
150158
finish(404, {});
151159
} else if (stat.isFile()) { // Stream a single file.
@@ -216,7 +224,7 @@ Server.prototype.respondGzip = function (pathname, status, contentType, _headers
216224
const that = this;
217225
if (files.length == 1 && this.gzipOk(req, contentType)) {
218226
const gzFile = files[0] + ".gz";
219-
fs.stat(gzFile, function (e, gzStat) {
227+
tryStat(gzFile, function (e, gzStat) {
220228
if (!e && gzStat.isFile()) {
221229
const vary = _headers['Vary'];
222230
_headers['Vary'] = (vary && vary != 'Accept-Encoding' ? vary + ', ' : '') + 'Accept-Encoding';

test/integration/node-static-test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,4 +460,13 @@ suite.addBatch({
460460
assert.equal(body, 'hello world');
461461
}
462462
}
463+
}).addBatch({
464+
'handling malicious urls': {
465+
topic : function(){
466+
request.get(TEST_SERVER + '/%00', this.callback);
467+
},
468+
'should respond with 404' : function(error, response, body){
469+
assert.equal(response.statusCode, 404);
470+
}
471+
}
463472
}).export(module);

0 commit comments

Comments
 (0)