Tamas Hegedus Tamas Hegedus - 5 months ago 12
Node.js Question

Safe path.resolve without escaping from parent

I am writing an (expressjs) http service, which gets a relative path as user input on every call, reads a file from the filesystem based on that path, and processes it, like:

app.get("/api", (req, res, next) => {
var filePath = path.resolve("./datasource", req.query.path);
fs.readFile(filePath, "utf8", (err, data) => {
processData(data, (err, processed) => {
res.json(processed);
});
});
});


I stripped out error handling for clarity. The problem with this is that one could call the url
/api?path=../../../etc/passwd
, and that would leak information from the server itself. I would like this api not to process files outside of the
./datasource
folder. I think I could use some customized implementation of
path.resolve
, which does not escape the parent, but it looks like to me there is no such functionality in the
path
module. Some examples I thought of:

saferesolve("./datasource", "a/b") === "./datasource/a/b"
saferesolve("./datasource", "a/b/../c") === "./datasource/a/c"
saferesolve("./datasource", "../..") === "./datasource"
saferesolve("./datasource", "../../a/b") === "./datasource/a/b"
saferesolve("./datasource", "../../a/b/..") === "./datasource/a"


Any ideas how to accomplish this without reinventing the whole
path
module?

Answer

This seems to pass your tests:

function saferesolve(base, target) {
  var targetPath = '.' + path.posix.normalize('/' + target)
  return path.posix.resolve(base, targetPath)
}