Metastatic.Analysis.BusinessLogic.UnrestrictedFileUpload
(Metastatic v0.10.4)
View Source
Detects unrestricted file upload vulnerabilities (CWE-434).
This analyzer identifies code patterns where file uploads are processed without proper validation of file type, size, or content.
Cross-Language Applicability
Unrestricted file upload is a universal web vulnerability:
- Elixir/Phoenix:
File.write!(path, upload.content)without validation - Python/Flask:
file.save(path)without checking extension - JavaScript/Express:
multerwithout file filter - Ruby/Rails:
file.attachwithout validation - PHP:
move_uploaded_file()without checks - Java/Spring:
transferTo()without validation - C#/ASP.NET:
SaveAs()without file type check
Problem
When file uploads lack validation:
- Attackers can upload executable files (web shells)
- Server can be compromised through uploaded malware
- Denial of service through large file uploads
- Storage exhaustion attacks
Detection Strategy
Detects patterns where:
- File save/write operations receive uploaded content
- No file type/extension validation is apparent
- No file size validation is apparent
- Original filename is used directly without sanitization
Examples
Bad (Elixir)
def upload(conn, %{"file" => upload}) do
path = "/uploads/#{upload.filename}"
File.write!(path, upload.path |> File.read!())
json(conn, %{status: "uploaded"})
endGood (Elixir)
@allowed_extensions ~w[.jpg .jpeg .png .gif]
@max_size 5_000_000
def upload(conn, %{"file" => upload}) do
ext = Path.extname(upload.filename) |> String.downcase()
size = File.stat!(upload.path).size
cond do
ext not in @allowed_extensions ->
conn |> put_status(400) |> json(%{error: "Invalid file type"})
size > @max_size ->
conn |> put_status(400) |> json(%{error: "File too large"})
true ->
safe_name = "#{UUID.uuid4()}#{ext}"
File.copy!(upload.path, "/uploads/#{safe_name}")
json(conn, %{status: "uploaded", filename: safe_name})
end
end