Here is my approch using multiple validations.
public class ImageValidator { private readonly Dictionary<string,byte[]> _validBytes = new Dictionary<string, byte[]>() { { ".bmp", new byte[] { 66, 77 } }, { ".gif", new byte[] { 71, 73, 70, 56 } }, { ".ico", new byte[] { 0, 0, 1, 0 } }, { ".jpg", new byte[] { 255, 216, 255 } }, { ".png", new byte[] { 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82 } }, { ".tiff", new byte[] { 73, 73, 42, 0 } }, }; /// <summary> /// image formats to validate using Guids from ImageFormat. /// </summary> private readonly Dictionary<Guid, string> _validGuids = new Dictionary<Guid, string>() { {ImageFormat.Jpeg.Guid, ".jpg" }, {ImageFormat.Png.Guid, ".png"}, {ImageFormat.Bmp.Guid, ".bmp"}, {ImageFormat.Gif.Guid, ".gif"}, {ImageFormat.Tiff.Guid, ".tiff"}, {ImageFormat.Icon.Guid, ".ico" } }; /// <summary> /// Supported extensions: .jpg,.png,.bmp,.gif,.tiff,.ico /// </summary> /// <param name="allowedExtensions"></param> public ImageValidator(string allowedExtensions = ".jpg;.png") { var exts = allowedExtensions.Split(';'); foreach (var pair in _validGuids.ToArray()) { if (!exts.Contains(pair.Value)) { _validGuids.Remove(pair.Key); } } foreach (var pair in _validBytes.ToArray()) { if (!exts.Contains(pair.Key)) { _validBytes.Remove(pair.Key); } } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0063:Use simple 'using' statement", Justification = "<Pending>")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "<Pending>")] public async Task<bool> IsValidAsync(Stream imageStream, string filePath) { if(imageStream == null || imageStream.Length == 0) { return false; } //First validate using file extension string ext = Path.GetExtension(filePath).ToLower(); if(!_validGuids.ContainsValue(ext)) { return false; } //Check mimetype by content if(!await IsImageBySigAsync(imageStream, ext)) { return false; } try { //Validate file using Guid. using (var image = Image.FromStream(imageStream)) { imageStream.Position = 0; var imgGuid = image.RawFormat.Guid; if (!_validGuids.ContainsKey(imgGuid)) { return false; } var validExtension = _validGuids[imgGuid]; if (validExtension != ext) { return false; } } } catch (OutOfMemoryException) { return false; } return true; } /// <summary> /// Validate the mimetype using byte and file extension. /// </summary> /// <param name="imageStream"></param> /// <param name="extension"></param> /// <returns></returns> private async Task<bool> IsImageBySigAsync(Stream imageStream, string extension) { var length = _validBytes.Max(x => x.Value.Length); byte[] imgByte = new byte[length]; await imageStream.ReadAsync(imgByte, 0, length); imageStream.Position = 0; if (_validBytes.ContainsKey(extension)) { var validImgByte = _validBytes[extension]; if (imgByte.Take(validImgByte.Length).SequenceEqual(validImgByte)) { return true; } } return false; } }