# HG changeset patch # User Gregory Szorc # Date 1491022046 25200 # Node ID 62f9679df1f2e2272465fea9e750c76df810cdd0 # Parent 161a87ed456ea8358a4a4d7f3ac0ed4ceed64c58 hgweb: extract path traversal checking into standalone function A common exploit in web applications that access paths is to insert path separator strings like ".." to try to get the server to serve up files it shouldn't. We have code for detecting this in staticfile(). A subsequent commit will need to perform this test as well. Since this is security code, let's factor the check so we don't have to reinvent the wheel. diff -r 161a87ed456e -r 62f9679df1f2 mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py Fri Mar 31 22:30:38 2017 -0700 +++ b/mercurial/hgweb/common.py Fri Mar 31 21:47:26 2017 -0700 @@ -135,6 +135,17 @@ def get_mtime(spath): return get_stat(spath, "00changelog.i").st_mtime +def ispathsafe(path): + """Determine if a path is safe to use for filesystem access.""" + parts = path.split('/') + for part in parts: + if (part in ('', os.curdir, os.pardir) or + pycompat.ossep in part or + pycompat.osaltsep is not None and pycompat.osaltsep in part): + return False + + return True + def staticfile(directory, fname, req): """return a file inside directory with guessed Content-Type header @@ -144,13 +155,10 @@ Return an empty string if fname is illegal or file not found. """ - parts = fname.split('/') - for part in parts: - if (part in ('', os.curdir, os.pardir) or - pycompat.ossep in part or - pycompat.osaltsep is not None and pycompat.osaltsep in part): - return - fpath = os.path.join(*parts) + if not ispathsafe(fname): + return + + fpath = os.path.join(*fname.split('/')) if isinstance(directory, str): directory = [directory] for d in directory: