Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 406
Tamas Hegedus Avatar asked May 01 '26 19:05

Tamas Hegedus


1 Answers

This seems to pass your tests:

function saferesolve(base, target) {
  var targetPath = '.' + path.posix.normalize('/' + target)
  return path.posix.resolve(base, targetPath)
}
like image 97
idbehold Avatar answered May 03 '26 07:05

idbehold