Skip to content

Path Traversal in s5cmd S3→Local Downloads (cp/sync) Leads to Arbitrary File Write & RCE #872

Open

Description

@Root1856

Summary:
s5cmd builds the local destination path of each downloaded object directly from the remote object key, with no sanitization against ../ traversal sequences. S3/GCS object keys are arbitrary byte strings and may legally contain .. and /. When a victim downloads a bucket/prefix with a wildcard (s5cmd cp "s3://bucket/*" dest/ or s5cmd sync ...), an attacker who can PutObject a single object with a crafted key (e.g. data/../../../../../../home/victim/.bashrc) causes the object's attacker-controlled contents to be written outside the destination directory, at the privilege level of the user running s5cmd.
The tainted key flows: parseBatch() returns the raw key (storage/url/url.go:412) → stored as relativePath and returned by Relative() (storage/url/url.go:171,342) → used as the object name in prepareLocalDestination() (command/cp.go:907) → dsturl.Join(objname), where URL.Join calls path.Join, which resolves the .. and escapes the destination (storage/url/url.go:200-216) → written via CreateTemp + Rename to the resolved absolute path (command/cp.go:629-652). sync has the identical sink at command/sync.go:532-547. No code anywhere validates that the final path stays within the chosen destination directory.

An attacker who can write a single object into a bucket/prefix that a victim later downloads with a wildcard (shared/multi-tenant buckets, ingestion/"drop" buckets, public-writable buckets, or a compromised lower-privilege producer feeding a higher-privilege consumer) achieves arbitrary local file write/overwrite with attacker-controlled contents at the privilege of the user running s5cmd. No victim credentials, MITM, or special flags are required — just a normal cp/sync download.
Because s5cmd is routinely invoked by automated and often privileged data-pipeline / CI jobs, this is a practical lower-privilege → higher-privilege escalation and remote code execution primitive: the attacker can overwrite files that the host subsequently executes — ~/.bashrc, ~/.profile, ~/.ssh/authorized_keys, CI build scripts, or /etc/cron.d/* (when run as root) — turning a routine bucket download into code execution on the victim machine.

Activity

  1. terryrankine commented on Sep 18, 2026

    @terryrankine

    Confirmed: with a key like data/../../../escape.txt in a bucket, cp s3://bucket/* dest/ and sync both write the file outside dest/ on master.

    Fix in #886: the joined local path is checked against the destination and offending keys are rejected with an error (exit 1, other objects still copied). Unit + e2e tests included. A released build with the fix is available as terryrankine/s5cmd v2.4.1 for anyone who needs it before this lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions