Validating File Formats
FulcrumFS can verify that a file's actual content matches its claimed type before it is stored, rejecting mismatched or malformed uploads. This guide covers the format validation processor and the standalone FileFormat API.
Why validate content
An extension or a client-supplied MIME type is just a label and can be wrong or malicious. A user might rename malware.exe to document.pdf, or a browser might mislabel a download. FileFormat inspects the actual bytes (magic numbers and structural checks) to confirm the format, so a .pdf that is really something else is caught at the boundary rather than ending up in storage, in a backup, and eventually back out to another user.
Caution
Never rely on the extension or MIME type alone for security-sensitive decisions. A pipeline that stores user uploads without verifying the content is trusting a value the client controls. For images and videos, use ImageProcessor or VideoProcessor (which both validate as part of decoding); for other content types, add a FileFormatValidationProcessor to the pipeline.
When to reach for the validation processor
FileFormatValidationProcessor is a lightweight check based on file headers and structural sanity. It is the right choice when:
- You accept content types that no FulcrumFS processor handles (PDFs, Office documents, ZIPs, plain text, etc.) and just need to confirm the bytes match the declared extension before storing.
- You want a cheap, dependency-free guard in a project that does not need full ImageSharp or FFmpeg processing.
It is not needed alongside ImageProcessor or VideoProcessor: those processors are supersets of the validator for their respective formats. They fully decode the source (which is a much stronger check than a header sanity scan) and reject malformed inputs as part of normal processing.
The Validation Processor
Add a FileFormatValidationProcessor to a pipeline to reject content that does not match an allowed format. Configure it with FileFormatValidationOptions, passing the formats you accept.
// Document upload endpoint: accept PDFs and DOCX, reject anything else.
var pipeline = new FileProcessingPipeline(
new FileFormatValidationProcessor(
new FileFormatValidationOptions(FileFormat.Pdf, FileFormat.Docx)));
var added = await txn.AddAsync(source, ".pdf", leaveOpen: true, pipeline);
When the content matches none of the allowed formats, the processor fails the add with a FileProcessingException, which an upload handler can translate into an HTTP 400. See Exception Handling.
Built-In Formats
FileFormat exposes static singletons for common types:
- Images: Jpeg, Png, Gif, WebP, Bmp, Tiff, Heic, Heif, Avif.
- Video and audio: Mp4, Mov, Mkv, WebM, M4a, plus the 3GPP family (Tgp, Tg2) and Mj2.
- Documents: Pdf, the OOXML family (Docx, Xlsx, Pptx), the OpenDocument family (Odt, Ods), and the legacy Doc binary format.
- Archives: Zip.
Each declares its Name, its Extensions, and a PrimaryExtension, which is useful when you want to normalize the stored extension to a canonical form regardless of how the uploader spelled it (for example, accepting both .jpg and .jpeg and storing as .jpg).
Text and catch-all factories
For content that is not a binary format, factory methods produce formats on demand: AnyContent accepts any bytes, TextAscii accepts ASCII text, TextUnicode accepts Unicode text, and TextEncoding accepts text in a specific Encoding. Each takes the extensions it should apply to. These are useful for validating uploads that should be plain text, for example a CSV import:
var csvValidator = new FileFormatValidationProcessor(
new FileFormatValidationOptions(FileFormat.TextAscii(".csv")));
Standalone Validation
The validation API lives in Singulink.FulcrumFS.Core and does not require a repository, so a client or front-end project can validate before upload. Call ValidateAsync on a stream to get a FileFormatValidationResult.
// In a desktop client, check the file before uploading it.
await using var stream = File.OpenRead(path);
var result = await FileFormat.Png.ValidateAsync(stream);
if (!result.IsValid)
{
MessageBox.Show("Please choose a valid PNG image.");
return;
}
This makes it possible to share the same format definitions between client-side pre-checks (for a snappier user experience) and server-side enforcement (for the actual trust boundary).
Important
Client-side validation is a convenience, not a substitute for server-side validation. Always validate again on the server, since a malicious client can simply skip the check.
Next Steps
- Processing Pipelines - Where validation fits in a pipeline.
- Image Processing - Image-specific validation and transformation.
- Exception Handling - Handling validation failures.