Summary
zip:unzip/1,2 and zip:extract/1,2 are vulnerable to a relative path traversal attack. A crafted zip archive containing entry names such as ../x/y can cause files to be written outside the intended extraction directory.
Details
check_dir_level/2 validates zip entry paths by tracking directory depth as a running integer counter: .. decrements it, normal directories increment it. The caller rejects only paths where the final counter value is < 0.
This check is insufficient. A path like ../x/y causes the counter to go negative mid-traversal (.. → -1) then recover (x → 0, base case on y → returns level 0). Because the final level is 0, not negative, the path passes validation. When joined with the extraction directory via add_cwd, it resolves to CWD/../x/y, one directory above the intended extraction root.
Impact
An attacker who can supply a crafted zip archive to an application that calls zip:unzip or zip:extract can write arbitrary files to any path reachable from the extraction directory by traversal. Depending on the application's privileges, this can enable remote code execution (overwriting scripts, configuration files, or shared libraries) or data corruption.
Affected/Unaffected Versions
A version larger than or equal to one of the listed patched versions is unaffected; otherwise, a version that satisfies an expression listed under affected versions is affected, and if it does not, it is unaffected.
The documentation of the new OTP version scheme describes how versions should be compared. Note that versions used prior to OTP 17.0, when the new OTP version scheme was introduced, are never listed since it is not well defined how to compare those versions.
Credits
Thanks to Jonatan Männchen and Zhang Delong for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.
Summary
zip:unzip/1,2andzip:extract/1,2are vulnerable to a relative path traversal attack. A crafted zip archive containing entry names such as../x/ycan cause files to be written outside the intended extraction directory.Details
check_dir_level/2validates zip entry paths by tracking directory depth as a running integer counter:..decrements it, normal directories increment it. The caller rejects only paths where the final counter value is< 0.This check is insufficient. A path like
../x/ycauses the counter to go negative mid-traversal (..→-1) then recover (x→0, base case ony→ returns level0). Because the final level is0, not negative, the path passes validation. When joined with the extraction directory viaadd_cwd, it resolves toCWD/../x/y, one directory above the intended extraction root.Impact
An attacker who can supply a crafted zip archive to an application that calls
zip:unziporzip:extractcan write arbitrary files to any path reachable from the extraction directory by traversal. Depending on the application's privileges, this can enable remote code execution (overwriting scripts, configuration files, or shared libraries) or data corruption.Affected/Unaffected Versions
A version larger than or equal to one of the listed patched versions is unaffected; otherwise, a version that satisfies an expression listed under affected versions is affected, and if it does not, it is unaffected.
The documentation of the new OTP version scheme describes how versions should be compared. Note that versions used prior to OTP 17.0, when the new OTP version scheme was introduced, are never listed since it is not well defined how to compare those versions.
Credits
Thanks to Jonatan Männchen and Zhang Delong for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.