An uploaded file is untrusted input with a name attached.

IFormFile.FileName and IFormFile.ContentType come from the client, and the extension is derived from that untrusted filename. They can help reject obvious mistakes, but none of them proves what the file contains or whether it is safe to process. Keep the original name only as untrusted metadata and HTML-encode it when displayed.

Build the upload policy from the business requirement:

  • require authentication and authorization, and protect browser upload endpoints against CSRF when credentials are sent automatically
  • allowlist only the extensions and parsed formats the feature needs
  • enforce file and request-size limits
  • generate the storage name in the application
  • verify a known file signature where the format supports it
  • parse content with maintained libraries configured for bounded resource use

A matching extension or signature is one signal, not a security verdict. A structurally valid image, PDF, or document can still exploit a vulnerable parser or carry malicious content.

Write new uploads to bounded quarantine or staging storage. For filesystem storage, keep that location outside the application and web-root directories. Do not serve that location publicly, and disable execution there when the storage platform supports it. Do not expose the file through normal download paths while its status is pending.

Run malware scanning when the threat model requires it, together with any format-specific validation, before promotion to normal storage. Record the validation state separately from the object itself, and bind it to an immutable object version or cryptographic content hash so it cannot be reused after the file changes. Treat pending, failed, timed-out, and unknown states as unavailable. Promote the file only after every required check records an explicit success. Delete rejected and abandoned uploads according to a defined cleanup policy.

Archives and compressed formats need additional limits. Bound the number of entries, nesting depth, and total extracted size. Resolve each entry against the extraction directory and verify that its canonical destination remains inside that directory. Reject absolute paths, traversal attempts, and link entries unless the use case explicitly supports them.

Request-body limits protect transport and server resources. They do not establish trust. Keep the file unavailable until every required validation step has passed.