ASP.NET Core  

Secure File Uploads in ASP.NET Core: Validation, Storage, and Best Practices

Allowing users to upload files is a common requirement for modern applications. Profile pictures, invoices, PDFs, Excel spreadsheets, images, and other documents are frequently uploaded through ASP.NET Core applications. While file uploads appear straightforward, they also introduce significant security and performance risks if not implemented correctly.

Unrestricted file uploads can lead to malware distribution, remote code execution, denial-of-service attacks, storage exhaustion, and sensitive data exposure. ASP.NET Core provides the building blocks for secure file handling, but developers must combine validation, storage, and security best practices to build a production-ready solution.

Rather than accepting uploaded files blindly, this article explains how to validate, store, and protect uploaded files in ASP.NET Core.

Note: Never trust any information provided by the client, including file names, file extensions, MIME types, or file sizes. Always validate uploads on the server.

Why Secure File Uploads Matter

Improper file upload handling can result in:

  • Malware uploads

  • Remote code execution

  • Storage exhaustion

  • Large file denial-of-service attacks

  • Unauthorized file access

  • Data leakage

  • Compliance violations

A secure upload pipeline protects both your infrastructure and your users.

Common File Upload Scenarios

Typical upload scenarios include:

  • Profile images

  • PDF documents

  • Excel spreadsheets

  • Product images

  • Medical records

  • User attachments

  • Video uploads

  • Invoice documents

Each scenario may require different validation and storage policies.

File Upload Workflow

flowchart LR

A[Client]
B[ASP.NET Core API]
C{Validate File}
D[Virus Scan]
E[(File Storage)]
F[(Database)]

A --> B
B --> C
C -->|Valid| D
C -->|Invalid| A
D -->|Safe| E
E --> F

Every uploaded file should pass through validation before being stored.

Accepting File Uploads

ASP.NET Core uses the IFormFile interface to represent uploaded files.

[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
    if (file == null)
        return BadRequest();

    return Ok();
}

IFormFile provides access to the uploaded file's name, size, content type, and stream.

Validate File Size

Large uploads can consume excessive server resources.

const long MaxFileSize = 5 * 1024 * 1024;

if (file.Length > MaxFileSize)
{
    return BadRequest("File exceeds size limit.");
}

Define upload limits based on business requirements rather than accepting arbitrarily large files.

Validate File Extension

Allow only supported file types.

var allowedExtensions =
    new[] { ".pdf", ".jpg", ".jpeg", ".png" };

var extension =
    Path.GetExtension(file.FileName)
        .ToLowerInvariant();

if (!allowedExtensions.Contains(extension))
{
    return BadRequest("Unsupported file type.");
}

Extension validation is only one layer of defense and should not be relied upon by itself.

Validate Content Type

Verify the MIME type supplied with the request.

var allowedTypes = new[]
{
    "application/pdf",
    "image/jpeg",
    "image/png"
};

if (!allowedTypes.Contains(file.ContentType))
{
    return BadRequest("Invalid content type.");
}

Content types can be spoofed, so combine this check with additional validation techniques.

Generate Safe File Names

Never store user-provided file names directly.

var fileName =
    $"{Guid.NewGuid()}{extension}";

Random file names prevent overwriting existing files and reduce the risk of path traversal attacks.

Save the Uploaded File

Store the file outside the web root whenever possible.

var path = Path.Combine(
    uploadsFolder,
    fileName);

using var stream =
    System.IO.File.Create(path);

await file.CopyToAsync(stream);

Keeping uploaded files outside wwwroot prevents direct public access.

Storage Options

Different applications require different storage strategies.

Storage OptionBest For
Local File SystemSmall internal applications
Azure Blob StorageCloud-native applications
Amazon S3AWS-hosted workloads
Network File ShareEnterprise environments
DatabaseSmall files requiring transactional consistency

Choose storage based on scalability, availability, and operational requirements.

Scan Uploaded Files

Production applications should scan uploaded files before making them available.

Common scanning solutions include:

  • Microsoft Defender

  • ClamAV

  • Commercial antivirus engines

  • Cloud malware scanning services

Scanning helps detect malicious content before users or downstream systems access uploaded files.

Protect Download Endpoints

Instead of exposing physical file paths, serve downloads through authenticated endpoints.

[Authorize]
[HttpGet("{id}")]
public IActionResult Download(Guid id)
{
    // Retrieve file securely

    return File(stream,
        contentType,
        downloadName);
}

Authorization ensures that only permitted users can access uploaded content.

Common Production Mistakes

ProblemRoot Cause
Executable files uploadedMissing extension validation
Storage exhaustionNo upload size limits
File overwriteUsing original file names
Public data exposureFiles stored inside wwwroot
Malware distributionNo antivirus scanning
Unauthorized downloadsMissing access control

Most upload vulnerabilities are caused by insufficient validation rather than framework limitations.

Best Practices

  • Validate file size before processing.

  • Restrict allowed file extensions.

  • Verify MIME types.

  • Generate unique file names.

  • Store uploads outside the web root.

  • Scan files for malware before use.

  • Protect download endpoints with authorization.

  • Log upload failures and security events.

Common Anti-Patterns

Avoid these common mistakes:

  • Trusting the original file name.

  • Accepting every file type.

  • Storing uploads inside publicly accessible folders.

  • Ignoring upload size limits.

  • Relying only on client-side validation.

  • Skipping malware scanning for user uploads.

FAQ

Is checking the file extension enough?

No. File extensions can be changed easily. Combine extension validation with MIME type validation and, where appropriate, file signature or antivirus scanning.

Should uploaded files be stored in the database?

Generally, no. Large files are usually better stored in dedicated file storage such as Azure Blob Storage or Amazon S3, while the database stores metadata.

Can I store uploads inside wwwroot?

It's generally safer to store uploaded files outside wwwroot and serve them through controlled endpoints that enforce authentication and authorization.

What's the maximum file size I should allow?

There is no universal limit. Configure upload limits based on your application's requirements while considering available storage, bandwidth, and security.

Conclusion

Secure file uploads require much more than simply accepting an IFormFile. A production-ready upload pipeline validates file size, extensions, and content types, generates safe file names, stores files securely, and restricts access through authenticated endpoints.

By combining proper validation, secure storage, malware scanning, and authorization, ASP.NET Core applications can safely handle user uploads while minimizing security risks and maintaining reliable performance in production.