ghsa-hm4x-r5hc-794f
Vulnerability from github
Heap Buffer Overflow in InterpretImageFilename
Summary
A heap buffer overflow was identified in the InterpretImageFilename
function of ImageMagick. The issue stems from an off-by-one error that causes out-of-bounds memory access when processing format strings containing consecutive percent signs (%%
).
Environment
- OS: Arch Linux (Linux gmkhost 6.14.2-arch1-1 # 1 SMP PREEMPT_DYNAMIC Thu, 10 Apr 2025 18:43:59 +0000 x86_64 GNU/Linux (GNU libc) 2.41)
- Architecture: x86_64
- Compiler: gcc (GCC) 15.1.1 20250425
Reproduction
Build Instructions
```bash
Clone the repository
git clone https://github.com/ImageMagick/ImageMagick.git cd ImageMagick git reset --hard 8fff9b4f44d2e8b5cae2bd6db70930a144d15f12
Build with AddressSanitizer
export CFLAGS="-fsanitize=address -g -O1" export CXXFLAGS="-fsanitize=address -g -O1" export LDFLAGS="-fsanitizer=address" ./configure make
Set library path and trigger the crash
export LD_LIBRARY_PATH="$(pwd)/MagickWand/.libs:$(pwd)/MagickCore/.libs:$LD_LIBRARY_PATH" ./utilities/.libs/magick %% a ```
Minimum Trigger
bash
./utilities/.libs/magick %% [any_output_filename]
Crash Analysis
AddressSanitizer Output
``` $ ./utilities/.libs/magick %% a ================================================================= ==2227694==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7037f99e3ad3 at pc 0x741801e81a17 bp 0x7ffd22fa4e00 sp 0x7ffd22fa45b8 READ of size 1 at 0x7037f99e3ad3 thread T0 #0 0x741801e81a16 in strchr /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:746 #1 0x7418013b4f06 in InterpretImageFilename MagickCore/image.c:1674 #2 0x7418012826a3 in ReadImages MagickCore/constitute.c:1040 #3 0x741800e4696b in CLINoImageOperator MagickWand/operation.c:4959 #4 0x741800e64de7 in CLIOption MagickWand/operation.c:5473 #5 0x741800d92edf in ProcessCommandOptions MagickWand/magick-cli.c:653 #6 0x741800d94816 in MagickImageCommand MagickWand/magick-cli.c:1392 #7 0x741800d913e4 in MagickCommandGenesis MagickWand/magick-cli.c:177 #8 0x5ef7a3546638 in MagickMain utilities/magick.c:162 #9 0x5ef7a3546872 in main utilities/magick.c:193 #10 0x7417ff53f6b4 (/usr/lib/libc.so.6+0x276b4) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) #11 0x7417ff53f768 in __libc_start_main (/usr/lib/libc.so.6+0x27768) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) #12 0x5ef7a3546204 in _start (/home/kforfk/workspace/fuzz_analysis/saigen/ImageMagick/utilities/.libs/magick+0x2204) (BuildId: 96677b60628cf297eaedb3eb17b87000d29403f2)
0x7037f99e3ad3 is located 0 bytes after 3-byte region [0x7037f99e3ad0,0x7037f99e3ad3) allocated by thread T0 here: #0 0x741801f20e15 in malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:67 #1 0x7418013e86bc in AcquireMagickMemory MagickCore/memory.c:559
SUMMARY: AddressSanitizer: heap-buffer-overflow MagickCore/image.c:1674 in InterpretImageFilename Shadow bytes around the buggy address: 0x7037f99e3800: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa 0x7037f99e3880: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa 0x7037f99e3900: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa 0x7037f99e3980: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa 0x7037f99e3a00: fa fa 07 fa fa fa fd fa fa fa fd fa fa fa 00 04 =>0x7037f99e3a80: fa fa 00 04 fa fa 00 00 fa fa[03]fa fa fa 03 fa 0x7037f99e3b00: fa fa 00 01 fa fa fa fa fa fa fa fa fa fa fa fa 0x7037f99e3b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7037f99e3c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7037f99e3c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7037f99e3d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==2227694==ABORTING ```
Root Cause Analysis
The first command line argument is interpreted as MagickImageCommand
:
https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/utilities/magick.c#L83
c
const CommandInfo
MagickCommands[] =
{
MagickCommandSize("magick", MagickFalse, MagickImageCommand),
It is invoked here:
https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L220
c
status=command(image_info,argc,argv,&text,exception);
The execution then follows this path: - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L1387 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L586 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L419 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L5391 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L5473 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L4959 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/constitute.c#L1009 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/constitute.c#L1039 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/image.c#L1649 - https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/image.c#L1674
The execution eventually reaches InterpretImageFilename
and enters a loop. The format
variable here is "%%"
. At this point, it is safe to access *(format + 2)
but not safe to access *(format + 3)
.
c
for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
{
q=(char *) p+1;
if (*q == '%')
{
p=q+1;
continue;
}
The first strchr
call returns a pointer equal to format
and assigns it to p
. Then q
is initialized with p + 1
(format + 1
), and *q
is '%'
, so the code enters the if branch. Here, p
is reassigned to q + 1
(format + 2
).
In the next iteration, p + 1
(format + 3
) is passed to strchr
, and when strchr
accesses it, this causes an out-of-bounds read.
{ "affected": [ { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-AnyCPU" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-AnyCPU" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-OpenMP-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-OpenMP-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-HDRI-x86" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-OpenMP-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-OpenMP-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q16-x86" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-AnyCPU" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-OpenMP-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-OpenMP-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-arm64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-x64" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] }, { "package": { "ecosystem": "NuGet", "name": "Magick.NET-Q8-x86" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "14.7.0" } ], "type": "ECOSYSTEM" } ] } ], "aliases": [ "CVE-2025-53014" ], "database_specific": { "cwe_ids": [ "CWE-125", "CWE-193" ], "github_reviewed": true, "github_reviewed_at": "2025-08-25T15:53:34Z", "nvd_published_at": "2025-07-14T18:15:23Z", "severity": "LOW" }, "details": "# Heap Buffer Overflow in InterpretImageFilename\n\n## Summary\nA heap buffer overflow was identified in the `InterpretImageFilename` function of ImageMagick. The issue stems from an off-by-one error that causes out-of-bounds memory access when processing format strings containing consecutive percent signs (`%%`).\n\n## Environment\n- **OS**: Arch Linux (Linux gmkhost 6.14.2-arch1-1 # 1 SMP PREEMPT_DYNAMIC Thu, 10 Apr 2025 18:43:59 +0000 x86_64 GNU/Linux (GNU libc) 2.41)\n- **Architecture**: x86_64\n- **Compiler**: gcc (GCC) 15.1.1 20250425\n\n## Reproduction\n\n### Build Instructions\n```bash\n# Clone the repository\ngit clone https://github.com/ImageMagick/ImageMagick.git\ncd ImageMagick\ngit reset --hard 8fff9b4f44d2e8b5cae2bd6db70930a144d15f12\n\n# Build with AddressSanitizer\nexport CFLAGS=\"-fsanitize=address -g -O1\"\nexport CXXFLAGS=\"-fsanitize=address -g -O1\"\nexport LDFLAGS=\"-fsanitizer=address\"\n./configure\nmake\n\n# Set library path and trigger the crash\nexport LD_LIBRARY_PATH=\"$(pwd)/MagickWand/.libs:$(pwd)/MagickCore/.libs:$LD_LIBRARY_PATH\"\n./utilities/.libs/magick %% a\n```\n\n### Minimum Trigger\n```bash\n./utilities/.libs/magick %% [any_output_filename]\n```\n\n## Crash Analysis\n\n### AddressSanitizer Output\n```\n$ ./utilities/.libs/magick %% a\n=================================================================\n==2227694==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7037f99e3ad3 at pc 0x741801e81a17 bp 0x7ffd22fa4e00 sp 0x7ffd22fa45b8\nREAD of size 1 at 0x7037f99e3ad3 thread T0\n #0 0x741801e81a16 in strchr /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:746\n #1 0x7418013b4f06 in InterpretImageFilename MagickCore/image.c:1674\n #2 0x7418012826a3 in ReadImages MagickCore/constitute.c:1040\n #3 0x741800e4696b in CLINoImageOperator MagickWand/operation.c:4959\n #4 0x741800e64de7 in CLIOption MagickWand/operation.c:5473\n #5 0x741800d92edf in ProcessCommandOptions MagickWand/magick-cli.c:653\n #6 0x741800d94816 in MagickImageCommand MagickWand/magick-cli.c:1392\n #7 0x741800d913e4 in MagickCommandGenesis MagickWand/magick-cli.c:177\n #8 0x5ef7a3546638 in MagickMain utilities/magick.c:162\n #9 0x5ef7a3546872 in main utilities/magick.c:193\n #10 0x7417ff53f6b4 (/usr/lib/libc.so.6+0x276b4) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35)\n #11 0x7417ff53f768 in __libc_start_main (/usr/lib/libc.so.6+0x27768) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35)\n #12 0x5ef7a3546204 in _start (/home/kforfk/workspace/fuzz_analysis/saigen/ImageMagick/utilities/.libs/magick+0x2204) (BuildId: 96677b60628cf297eaedb3eb17b87000d29403f2)\n\n0x7037f99e3ad3 is located 0 bytes after 3-byte region [0x7037f99e3ad0,0x7037f99e3ad3)\nallocated by thread T0 here:\n #0 0x741801f20e15 in malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:67\n #1 0x7418013e86bc in AcquireMagickMemory MagickCore/memory.c:559\n\nSUMMARY: AddressSanitizer: heap-buffer-overflow MagickCore/image.c:1674 in InterpretImageFilename\nShadow bytes around the buggy address:\n 0x7037f99e3800: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa\n 0x7037f99e3880: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa\n 0x7037f99e3900: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa\n 0x7037f99e3980: fa fa 07 fa fa fa 00 fa fa fa fd fa fa fa fd fa\n 0x7037f99e3a00: fa fa 07 fa fa fa fd fa fa fa fd fa fa fa 00 04\n=\u003e0x7037f99e3a80: fa fa 00 04 fa fa 00 00 fa fa[03]fa fa fa 03 fa\n 0x7037f99e3b00: fa fa 00 01 fa fa fa fa fa fa fa fa fa fa fa fa\n 0x7037f99e3b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x7037f99e3c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x7037f99e3c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n 0x7037f99e3d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\nShadow byte legend (one shadow byte represents 8 application bytes):\n Addressable: 00\n Partially addressable: 01 02 03 04 05 06 07 \n Heap left redzone: fa\n Freed heap region: fd\n Stack left redzone: f1\n Stack mid redzone: f2\n Stack right redzone: f3\n Stack after return: f5\n Stack use after scope: f8\n Global redzone: f9\n Global init order: f6\n Poisoned by user: f7\n Container overflow: fc\n Array cookie: ac\n Intra object redzone: bb\n ASan internal: fe\n Left alloca redzone: ca\n Right alloca redzone: cb\n==2227694==ABORTING\n```\n\n## Root Cause Analysis\nThe first command line argument is interpreted as `MagickImageCommand`:\nhttps://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/utilities/magick.c#L83\n```c\nconst CommandInfo\n MagickCommands[] =\n {\n MagickCommandSize(\"magick\", MagickFalse, MagickImageCommand),\n```\n\nIt is invoked here:\nhttps://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L220\n```c\nstatus=command(image_info,argc,argv,\u0026text,exception);\n```\n\nThe execution then follows this path:\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L1387\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L586\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/magick-cli.c#L419\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L5391\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L5473\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickWand/operation.c#L4959\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/constitute.c#L1009\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/constitute.c#L1039\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/image.c#L1649\n- https://github.com/ImageMagick/ImageMagick/blob/8fff9b4f44d2e8b5cae2bd6db70930a144d15f12/MagickCore/image.c#L1674\n\nThe execution eventually reaches `InterpretImageFilename` and enters a loop. The `format` variable here is `\"%%\"`. At this point, it is safe to access `*(format + 2)` but not safe to access `*(format + 3)`.\n\n```c\nfor (p=strchr(format,\u0027%\u0027); p != (char *) NULL; p=strchr(p+1,\u0027%\u0027))\n{\n q=(char *) p+1;\n if (*q == \u0027%\u0027)\n {\n p=q+1;\n continue;\n }\n```\n\nThe first `strchr` call returns a pointer equal to `format` and assigns it to `p`. Then `q` is initialized with `p + 1` (`format + 1`), and `*q` is `\u0027%\u0027`, so the code enters the if branch. Here, `p` is reassigned to `q + 1` (`format + 2`).\n\nIn the next iteration, `p + 1` (`format + 3`) is passed to `strchr`, and when `strchr` accesses it, this causes an out-of-bounds read.", "id": "GHSA-hm4x-r5hc-794f", "modified": "2025-08-25T15:53:35Z", "published": "2025-08-25T15:53:34Z", "references": [ { "type": "WEB", "url": "https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-hm4x-r5hc-794f" }, { "type": "ADVISORY", "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-53014" }, { "type": "WEB", "url": "https://github.com/ImageMagick/ImageMagick/commit/29d82726c7ec20c07c49ba263bdcea16c2618e03" }, { "type": "WEB", "url": "https://github.com/ImageMagick/ImageMagick6/commit/79b6ed03770781d996d1710b89fbb887e5ea758a" }, { "type": "PACKAGE", "url": "https://github.com/ImageMagick/ImageMagick" }, { "type": "WEB", "url": "https://github.com/dlemstra/Magick.NET/releases/tag/14.7.0" } ], "schema_version": "1.4.0", "severity": [ { "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N", "type": "CVSS_V3" } ], "summary": "ImageMagick has a Heap Buffer Overflow in InterpretImageFilename" }
Sightings
Author | Source | Type | Date |
---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.