We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Processing untrusted ZIP files can introduce zip bombs, excessive file creation, and directory traversal attacks.
Here are best practices to handle them securely.
Potential issues
Zip bomb
In computing, a zip bomb, also known as a decompression bomb or zip of death (ZOD), is a malicious archive file designed to crash or render useless the program or system reading it. The older the system or program, the less likely it is that the zip bomb will be detected.
A zip bomb is usually a small file for ease of transport and to avoid suspicion. However, when the file is unpacked, its contents are more than the system can handle.
Relative paths
If you decompress a zip file, but it includes the file: ../../../../../../vendor/config.exs
for example. this then overwrites your config.exs
file. This is a behaviour you don't want to happen.
A zillion inodes
A zip file may contain millions of 0 byte files, using up all your available inodes on the system. This would stop the hard disk being able to create new files on that partition. This could be medium-bad.
Limiting the Number of Files and Total Extracted Size
Before processing, check that the ZIP archive does not exceed reasonable limits in terms of extracted file size and file count:
def safe_zip?(file_path, max_files \\ 100, max_size \\ 10 * 1024 * 1024) do
case :zip.list_dir(file_path) do
{:ok, file_list} ->
total_size = Enum.reduce(file_list, 0, fn {_name, size}, acc -> acc + size end)
length(file_list) <= max_files && total_size <= max_size
_ ->
false
end
end
if safe_zip?(file_path) do
IO.puts("ZIP file within safe limits.")
else
IO.puts("ZIP file exceeds safe limits!")
end
✅ Mitigates: Zip bombs and excessive file creation
Blocking directory traversal attacks
Attackers might include filenames like ../../etc/passwd
inside a ZIP file. To prevent this, we reject filenames containing ../
or having the prefix /
:
def valid_filenames?(file_path) do
case :zip.list_dir(file_path) do
{:ok, file_list} ->
Enum.all?(file_list, fn {name, _size} ->
not String.contains?(name, "../") && not String.starts_with?(name, "/")
end)
_ ->
false
end
end
if valid_filenames?(file_path) do
IO.puts("No directory traversal risk detected.")
else
IO.puts("Potential directory traversal attack detected!")
end
✅ Mitigates: Arbitrary file writes and system compromise
Enforcing file size limits in Phoenix Uploads
Before processing files in a Phoenix app, ensure upload limits are enforced at the controller level:
def upload(conn, %{
"file" => %Plug.Upload{path: temp_path, filename: filename, content_type: mime}
}) do
if File.stat!(temp_path).size > 5 * 1024 * 1024 do
conn |> put_status(:bad_request) |> json(%{error: "File too large"})
else
# Continue processing
end
end
✅ Prevents: Large files from consuming excessive server resources
Conclusion
By applying these techniques, you can safely process zip files without exposing your system to common security vulnerabilities.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.