SecureFileUpload.AspNetCore
1.0.5
dotnet add package SecureFileUpload.AspNetCore --version 1.0.5
NuGet\Install-Package SecureFileUpload.AspNetCore -Version 1.0.5
<PackageReference Include="SecureFileUpload.AspNetCore" Version="1.0.5" />
<PackageVersion Include="SecureFileUpload.AspNetCore" Version="1.0.5" />
<PackageReference Include="SecureFileUpload.AspNetCore" />
paket add SecureFileUpload.AspNetCore --version 1.0.5
#r "nuget: SecureFileUpload.AspNetCore, 1.0.5"
#:package SecureFileUpload.AspNetCore@1.0.5
#addin nuget:?package=SecureFileUpload.AspNetCore&version=1.0.5
#tool nuget:?package=SecureFileUpload.AspNetCore&version=1.0.5
SecureFileUpload.AspNetCore
Drop-in ASP.NET Core 8 protection for file uploads. Register it once and multipart, raw binary, and marked base64 uploads are validated before controller code stores or processes the file.
Security Checks
The package validates the common upload attack paths:
- File name safety: Gujarati/English names up to 255 characters; allows letters, numbers, spaces,
.,-,_,(,); rejects path traversal, null bytes, reserved device names, bidi spoofing, and dangerous double extensions. - Extension policy: blocklist-first by default. Leave
AllowedFileTypesempty for general uploads, or set it per input throughCheckFile. - File size: per-file
MaxFileSizeBytesand request-levelMaxRequestBodySizeBytes. - Magic number/signature: catches renamed files such as
malware.exerenamed tophoto.jpg. - MIME cross-check: clearly wrong MIME values are rejected; empty/generic browser MIME values are treated as inconclusive to avoid false positives.
- Image dimensions: catches small image files that declare unsafe width/height/pixel counts.
- Polyglot/script detection: detects executable headers and script markers. Raster image compressed data is not scanned as plain text; only headers and appended trailer payloads are inspected to avoid false positives.
- Archive safety: recursive zip/docx/xlsx/pptx inspection, blocked entry extensions, executable/script content inside archives, nested archive depth, compression ratio, entry count, expanded size, corrupt archive, unreadable/encrypted entries, and zip-slip paths.
- Threat scanner hook: host apps can register
IFileThreatScannerfor ClamAV/cloud AV scanning. - PDF inspection: iText 8.0.5 (also used by the host app) resolves PDF objects, escaped names, indirect lengths and compressed object tables. Binary stream data is excluded from generic text matching; JavaScript and launch actions are rejected. Non-stream bytes, including appended payloads, retain script and executable checks. This also applies to PDFs inside archives.
The built-in threat scanner is a no-op so existing apps do not break. For high-risk systems, register ClamAV or a cloud malware scanner before files are stored or made available to other users.
Setup
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSecureFileUpload(builder.Configuration);
builder.WebHost.ConfigureKestrel(o =>
o.Limits.MaxRequestBodySize =
builder.Configuration.GetValue<long>("SecureFileUpload:MaxRequestBodySizeBytes"));
var app = builder.Build();
app.UseRouting();
app.UseSecureFileUpload();
app.MapControllers();
app.Run();
Configuration
{
"SecureFileUpload": {
"Enabled": true,
"AllowedFileTypes": [],
"BlockedExtensions": [ ".exe", ".dll", ".php", ".js", ".sh", ".bat", ".ps1", ".cmd", ".com", ".msi", ".vbs", ".vbe", ".jse", ".wsf", ".jar", ".scr", ".hta", ".lnk", ".reg", ".cpl", ".gadget", ".msc", ".apk", ".app", ".dmg", ".pkg", ".deb", ".rpm", ".docm", ".xlsm", ".pptm", ".svg", ".html", ".htm", ".xhtml" ],
"MaxFileSizeBytes": 5242880,
"MaxRequestBodySizeBytes": 26214400,
"RequireFileExtension": false,
"MaxFileNameLength": 255,
"EnforceImageDimensionCheck": true,
"MaxImageWidth": 10000,
"MaxImageHeight": 10000,
"MaxImagePixels": 50000000,
"EnforceSignatureCheck": true,
"EnforceMimeTypeCheck": true,
"EnforcePolyglotCheck": true,
"BlockZipArchivesWithHighCompressionRatio": true,
"MaxZipCompressionRatio": 100,
"MaxArchiveEntries": 1000,
"MaxArchiveUncompressedBytes": 209715200,
"MaxArchiveDepth": 3,
"MaxArchiveEntryBytes": 52428800,
"BlockArchivesContainingUnsafeFiles": true,
"BlockUnreadableArchiveEntries": true,
"EnableThreatScanner": true,
"MaxFilesPerRequest": 10,
"ExcludedPaths": [ "/api/admin/import" ]
}
}
Per-Input Server Validation
Use CheckFileAsync when one upload input has its own file type and size rule.
The result includes file name, field name, extension, content type, size, error
codes, and ErrorMessage.
using SecureFileUpload.Models;
using SecureFileUpload.Validation;
public class DocumentsController : Controller
{
private readonly IFileValidator _fileValidator;
public DocumentsController(IFileValidator fileValidator)
{
_fileValidator = fileValidator;
}
[HttpPost]
public async Task<IActionResult> Upload(IFormFile document)
{
var result = await _fileValidator.CheckFileAsync(
document,
new FileCheckOptions
{
FieldName = nameof(document),
AllowedFileTypes = new[] { ".pdf", ".jpg", ".jpeg", ".png" },
MaxFileSizeBytes = FileCheckOptions.Megabytes(5)
});
if (!result.IsValid)
{
return BadRequest(result);
}
return Ok();
}
}
Short overload:
var result = await _fileValidator.CheckFileAsync(
document,
new[] { ".pdf", ".jpg", ".png" },
FileCheckOptions.Megabytes(5));
For byte-array/API/base64 workflows:
var result = _fileValidator.CheckFile(
fileName,
declaredContentType,
bytes,
new[] { ".pdf", ".jpg" },
FileCheckOptions.Megabytes(2));
Client Toast and CheckFile Helper
The package ships optional static web assets:
<link rel="stylesheet" href="~/_content/SecureFileUpload.AspNetCore/css/secure-upload-toast.css" />
<script src="~/_content/SecureFileUpload.AspNetCore/js/secure-upload-client.js"></script>
Developer-side input validation:
const result = window.SecureUpload.CheckFile("#Document", ".pdf,.jpg,.png", 5);
if (!result.isValid) {
console.log(result.message);
}
5 means 5 MB by default. You can also pass bytes:
window.SecureUpload.CheckFile("#Document", [".pdf", ".jpg"], 5242880, {
sizeUnit: "bytes"
});
Automatic validation through markup:
<input type="file"
id="Document"
accept=".pdf,.jpg,.png"
data-secure-upload-size="5"
multiple />
The helper shows the same toast style and returns the full message with file info.
The client understands both camelCase and PascalCase server validation payloads,
so older package responses like Success/Message/Files do not leak raw JSON into
the toast.
Base64 JSON Uploads
public class UploadDocumentRequest
{
public string DocumentName { get; set; } = string.Empty;
[Base64File(FileNameProperty = nameof(DocumentName))]
public string FileContent { get; set; } = string.Empty;
}
Malware Scanner Hook
Register your own scanner to replace the default no-op scanner:
using SecureFileUpload.Scanning;
builder.Services.AddSingleton<IFileThreatScanner, ClamAvFileThreatScanner>();
builder.Services.AddSecureFileUpload(builder.Configuration);
Return FileThreatScanResult.Unsafe("ThreatName") to block the upload with a
stable MALWARE_DETECTED error code. If the scanner throws, the validator fails
closed with MALWARE_SCAN_FAILED.
Example Rejection Response
{
"success": false,
"message": "One or more uploaded files failed validation.",
"files": [
{
"fieldName": "document",
"fileName": "invoice.jpg",
"extension": ".jpg",
"declaredContentType": "image/jpeg",
"fileSizeBytes": 14804,
"isValid": false,
"errorMessage": "File content does not match the expected binary signature for a '.jpg' file. The extension may have been spoofed.",
"errors": [
{
"code": "SIGNATURE_MISMATCH",
"message": "File content does not match the expected binary signature for a '.jpg' file. The extension may have been spoofed."
}
]
}
]
}
Building the Package
dotnet pack -c Release
The package is written to bin/Release/SecureFileUpload.AspNetCore.<version>.nupkg.
The web application references the local SecureFileUpload project so builds
include the corrected validator. Other consumers can use package version 1.0.5.
Run the smoke validation matrix (PDF fixtures use iText and its crypto adapter):
dotnet run --project ..\SecureFileUpload.Tests\SecureFileUpload.Tests.csproj -c Release
To assert that a customer sample passes both the validator and multipart middleware:
dotnet run --project ..\SecureFileUpload.Tests\SecureFileUpload.Tests.csproj -c Release -- --expect-valid "D:\Sample_script_pdf\virumidiaBillNo28.pdf"
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- itext7 (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Uses PDF object inspection to avoid script false positives in compressed
image streams while rejecting PDF JavaScript and launch actions.
Adds IFileValidator.CheckFile/CheckFileAsync for per-input file type and size
validation, richer validation result metadata, blocklist-first defaults, MIME
false-positive fixes, recursive archive inspection, image dimension limits,
a malware scanner hook, PNG/JPEG/GIF/BMP/WebP false-positive fixes, basic
PDF corruption detection, 255-character Gujarati/English filename support,
an Enabled switch, and packaged toast/client helper assets.