You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Path Traversal in s5cmd S3→Local Downloads (cp/sync) Leads to Arbitrary File Write & RCE #872
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.
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.
Activity
terryrankine commentedon Sep 18, 2026
Confirmed: with a key like
data/../../../escape.txtin a bucket,cp s3://bucket/* dest/andsyncboth write the file outsidedest/onmaster.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.