# Directory Traversal
**Directory traversal** vulnerabilities allow attackers to access arbitrary files on your server by manipulating HTTP parameters to include relative path syntax. It is important that you treat any parameters used to refer to files securely, or an attacker will be able to read sensitive data from your file system. Even better, avoid direct references to filenames altogether and use opaque identifiers and indirection instead.
## Directory Traversal in Python
Passing file paths in URLs is dangerous. Consider the following Flask application that hosts menus for a restaurant:
“`python @app.route(‘/menus’) def download_menu(): “””An insecure static file handler that allows directory traversal attacks.”””filename = request.args.get(‘menu’) static_directory = os.fspath(app.menu_folder)# The construction of the path here is incredibly insecure! # If a path contains the “..%2F” pattern, it will be treated as # ../ and a hacker can climb out of the static directory. filename = posixpath.join(static_directory, filename) return send_file(filename) |
Here the name of the menu corresponds to a file on disk, which is being passed in the query string parameter. An attacker can set this `menu` parameter to anything they choose, and use the `../` syntax to access other directories. In fact, the URL `/menus?menu=../certs/key.pem` will let them download the server’s private key kept in a directory next to the menus.
If you take file paths from the HTTP request, make sure to strip any characters that can be used in files paths, such as `/`, `..`, `\` and`~`. These characters vary by operating system and can be encoded in subtle ways, so it’s generally best to disallow *all* non-alphanumeric characters:
“`python @app.route(‘/menus’) def download_menu(): “””An more secure file handler does not allow directory traversal attacks.”””filename = request.args.get(‘menu’) safe_filename = re.sub(‘[^0-9a-zA-Z\.]+’, ‘_’, filename) static_directory = os.fspath(app.menu_folder) filename = os.path.join(static_directory, safe_filename)return send_file(filename) “` |
In most web-servers you can have the server take care of this for you. The following function safely mounts
the `/var/etc/menus` directory as static content using the Flask web-server:
“`python @app.route(‘/menus/<path:path>’) def download_menu(path): return send_from_directory(‘/var/etc/menus’, path) “` |
## Other Considerations
If your website is handling a lot of static documents, consider using or integrating a third-party *Content Management System* (CMS). These will generate secure paths for documents as they are uploaded and allow fine-grained permissions to be set.
## CWEs
* [CWE-23](https://cwe.mitre.org/data/definitions/23.html)