Filename sanitization improvement in download_file function #4964
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
to a large audience (ideally all users of OctoPrint)
made sure your changes don't interfere with current development by
talking it through with the maintainers, e.g. through a
Brainstorming ticket
devel
branch if it's a completelynew feature, or
maintenance
if it's a bug fix or improvement ofexisting functionality for the current stable version (no PRs
against
master
or anything else please)(no PRs from your version of
master
,maintenance
, ordevel
please), e.g.
dev/my_new_feature
orfix/my_bugfix
no dead code, ideally only one commit - rebase and squash your PR
if necessary!
.less
source files, not the.css
files (those are generatedwith
lessc
)have added unit tests
nothing broke
AUTHORS.md
file :)What does this PR do and why is it necessary?
The
download_file
function in/octoprint/OctoPrint/src/octoprint/util/net.py
suffers from a quasi - Path Traversal vulnerability:OctoPrint/src/octoprint/util/net.py
Lines 260 to 283 in 65a5533
As visible on line 277, the filename of the file to be downloaded, taken from the
Content-Disposition
header received from the remote server during file download, is not sanitized and is appended directly to the folder name.The presence of the
assert path.startswith(folder)
instruction on line 278 prevents Path Traversal towards the parent of the folder, but not within subfolders. Taking for example a case in which the function was called with the intention of storing the file inside/
, if the server responded with the headerContent-Disposition: attachment; filename=etc/passwd
, the downloaded file would overwrite/etc/passwd
.I'm sending a PR instead of using the GitHub Advisory tool because in the current codebase the
download_file
function is only called by specifying temporary folders as the folder, so this vulnerability is not exploitable. However, I believe that improving filename sanitization in this case is easy and prevents any vulnerabilities that might arise by reusing thedownload_file
function differently in the future.How was it tested? How can it be tested by the reviewer?
I have verified that the unit tests pass.
I don't seem to see any situations where this change would break anything.
The function I added,
secure_filename
, takes care of sanitizing file names and is specifically designed to pass the sanitized filename toos.path.join()
, as documented in the Flask documentation.However, I'm open to discussion if you notice any edge cases that I missed.