Skip to content

Commit a77c494

Browse files
authored
Validate image bounds before decoding (#11)
This PR adds metadata validation before full image decode in the img and dir commands.
1 parent c6d94dc commit a77c494

3 files changed

Lines changed: 52 additions & 2 deletions

File tree

src/PrivatePdfConverter/Commands/DirToPdf.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,16 @@ public static void ConvertDirectoryToOnePdf(string path, string? output)
2323
}
2424

2525
using var images = new MagickImageCollection();
26-
supportedFiles.ForEach(x => images.Add(new MagickImage(x)));
26+
foreach (var file in supportedFiles)
27+
{
28+
var image = FileService.LoadValidatedImage(file);
29+
if (image is null)
30+
{
31+
return;
32+
}
33+
34+
images.Add(image);
35+
}
2736

2837
SaveAsPdf(path, images, output);
2938
}

src/PrivatePdfConverter/Commands/ImgToPdf.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ public static void ConvertImageToOnePdf(string path, string? output)
2323
Log.Logger.Information("Read 1 file with name: {FileName}, Full path: '{Path}'", Path.GetFileName(path), path);
2424

2525
using var images = new MagickImageCollection();
26-
images.Add(new MagickImage(path));
26+
var image = FileService.LoadValidatedImage(path);
27+
if (image is null)
28+
{
29+
return;
30+
}
2731

32+
images.Add(image);
2833
SaveAsPdf(path, images, output);
2934
}
3035

src/PrivatePdfConverter/Services/FileService.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
using ImageMagick;
12
using Serilog;
23

34
namespace PrivatePdfConverter.Services;
45

56
public static class FileService
67
{
8+
// Conservative defaults chosen to allow typical high-resolution images
9+
// while rejecting obviously pathological dimensions before full decode.
10+
private const ulong MaxWidth = 10_000;
11+
private const ulong MaxHeight = 10_000;
12+
private const ulong MaxArea = 100_000_000;
13+
714
public static IEnumerable<string> ValidExtensions { get; } =
815
[
916
"jpg", "jpeg", "bmp", "gif", "png", "tif", "tiff", "webp"
@@ -12,6 +19,35 @@ public static class FileService
1219
public static bool IsImage(this string? extension)
1320
=> !string.IsNullOrEmpty(extension) && ValidExtensions.Contains(extension.ToLower()[1..]);
1421

22+
public static MagickImage? LoadValidatedImage(string path)
23+
{
24+
using var headerImage = new MagickImage();
25+
headerImage.Ping(path);
26+
27+
var width = headerImage.Width;
28+
var height = headerImage.Height;
29+
var area = (ulong)width * height;
30+
31+
if (width == 0 || height == 0)
32+
{
33+
Log.Logger.Error("Image '{Path}' has invalid dimensions {Width}x{Height}.", path, width, height);
34+
return null;
35+
}
36+
37+
if (width > MaxWidth || height > MaxHeight || area > MaxArea)
38+
{
39+
Log.Logger.Error(
40+
"Image '{Path}' exceeds the supported limits ({Width}x{Height}, area {Area}).",
41+
path,
42+
width,
43+
height,
44+
area);
45+
return null;
46+
}
47+
48+
return new MagickImage(path);
49+
}
50+
1551
public static IEnumerable<string> LoadFilePathsFromDirectory(this string path, string searchPattern = "*")
1652
{
1753
var files = Directory.GetFiles(path, searchPattern).ToList();

0 commit comments

Comments
 (0)