VYPR
Unrated severityNVD Advisory· Published Aug 25, 2022· Updated Aug 3, 2024

CVE-2021-20224

CVE-2021-20224

Description

Integer overflow in ImageMagick's ExportIndexQuantum() can cause undefined behavior or crash when processing crafted PDF files.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Integer overflow in ImageMagick's ExportIndexQuantum() can cause undefined behavior or crash when processing crafted PDF files.

Vulnerability

An integer overflow vulnerability exists in ImageMagick's ExportIndexQuantum() function in MagickCore/quantum-export.c. The GetPixelIndex() function can return values outside the range of representable values for unsigned char. When these values are directly cast to unsigned char without an intermediate cast to ssize_t, the truncation can lead to undefined behavior. This vulnerability affects ImageMagick versions prior to the commits that introduced the ssize_t cast ([1], [3]).

Exploitation

An attacker can exploit this vulnerability by providing a crafted PDF file to an ImageMagick instance. No special privileges or authentication are required. When ImageMagick processes the malicious PDF, the ExportIndexQuantum() function is called, and the integer overflow occurs, potentially leading to crashes or other undefined behavior.

Impact

Successful exploitation can result in undefined behavior, including application crashes (denial of service). The full extent of impact is not documented, but it may also lead to information disclosure or other undefined outcomes.

Mitigation

The issue has been fixed in the ImageMagick codebase by casting the result of GetPixelIndex() to ssize_t before converting to unsigned char ([1], [3]). Users should update to a version of ImageMagick that includes this fix (e.g., commits 553054c1cb1e4e05ec86237afef76a32cd7c464d and 5af1dffa4b6ab984b5f13d1e91c95760d75f12a6). No workaround is available other than applying the patch or upgrading.

AI Insight generated on May 24, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

13

Patches

4
61a2a80af355

pending release

1 file changed · +1 1
  • ChangeLog+1 1 modified
    @@ -1,5 +1,5 @@
     2021-01-09  7.0.10-57  <quetzlzacatenango@image...>
    -  * Release ImageMagick version 7.0.10-57 GIT revision 18218:d7a3d75ff:20210109 
    +  * Release ImageMagick version 7.0.10-57 GIT revision 18221:2f611d533:20210109
     
     2021-01-08  7.0.10-57  <quetzlzacatenango@image...>
       * update automake/autoconf configuration files.
    
1afccc12e29c

pending release

1 file changed · +1 1
  • ChangeLog+1 1 modified
    @@ -1,5 +1,5 @@
     2021-01-09  6.9.11-57  <quetzlzacatenango@image...>
    -  * Release ImageMagick version 6.9.11-57 GIT revision 16299:653bda373:20210109
    +  * Release ImageMagick version 6.9.11-57 GIT revision 16301:c2f75ef89:20210109
     
     2021-01-08  6.9.11-57  <quetzlzacatenango@image...>
       * update automake/autoconf configuration files.
    
553054c1cb1e

https://github.com/ImageMagick/ImageMagick/pull/3083

1 file changed · +37 32
  • magick/quantum-export.c+37 32 modified
    @@ -2516,21 +2516,21 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
     
           for (x=((ssize_t) number_pixels-7); x > 0; x-=8)
           {
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q=((pixel & 0x01) << 7);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 6);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 5);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 4);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 3);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 2);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 1);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 0);
             q++;
           }
    @@ -2539,7 +2539,7 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
               *q='\0';
               for (bit=7; bit >= (ssize_t) (8-(number_pixels % 8)); bit--)
               {
    -            pixel=(unsigned char) *indexes++;
    +            pixel=(unsigned char) ((ssize_t) *indexes++);
                 *q|=((pixel & 0x01) << (unsigned char) bit);
               }
               q++;
    @@ -2553,15 +2553,15 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
     
           for (x=0; x < (ssize_t) (number_pixels-1) ; x+=2)
           {
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q=((pixel & 0xf) << 4);
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0xf) << 0);
             q++;
           }
           if ((number_pixels % 2) != 0)
             {
    -          pixel=(unsigned char) *indexes++;
    +          pixel=(unsigned char) ((ssize_t) *indexes++);
               *q=((pixel & 0xf) << 4);
               q++;
             }
    @@ -2669,25 +2669,25 @@ static void ExportIndexAlphaQuantum(const Image *image,
     
           for (x=((ssize_t) number_pixels-3); x > 0; x-=4)
           {
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q=((pixel & 0x01) << 7);
             pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
               TransparentOpacity ? 1 : 0);
             *q|=((pixel & 0x01) << 6);
             p++;
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 5);
             pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
               TransparentOpacity ? 1 : 0);
             *q|=((pixel & 0x01) << 4);
             p++;
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 3);
             pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
               TransparentOpacity ? 1 : 0);
             *q|=((pixel & 0x01) << 2);
             p++;
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q|=((pixel & 0x01) << 1);
             pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
               TransparentOpacity ? 1 : 0);
    @@ -2700,7 +2700,7 @@ static void ExportIndexAlphaQuantum(const Image *image,
               *q='\0';
               for (bit=3; bit >= (ssize_t) (4-(number_pixels % 4)); bit-=2)
               {
    -            pixel=(unsigned char) *indexes++;
    +            pixel=(unsigned char) ((ssize_t) *indexes++);
                 *q|=((pixel & 0x01) << (unsigned char) (bit+4));
                 pixel=(unsigned char) (GetPixelOpacity(p) == (Quantum)
                   TransparentOpacity ? 1 : 0);
    @@ -2718,10 +2718,10 @@ static void ExportIndexAlphaQuantum(const Image *image,
     
           for (x=0; x < (ssize_t) number_pixels ; x++)
           {
    -        pixel=(unsigned char) *indexes++;
    +        pixel=(unsigned char) ((ssize_t) *indexes++);
             *q=((pixel & 0xf) << 4);
    -        pixel=(unsigned char) (16*QuantumScale*((Quantum) (QuantumRange-
    -          GetPixelOpacity(p)))+0.5);
    +        pixel=(unsigned char) ((ssize_t) (16*QuantumScale*((Quantum)
    +          (QuantumRange-GetPixelOpacity(p)))+0.5));
             *q|=((pixel & 0xf) << 0);
             p++;
             q++;
    @@ -2752,7 +2752,8 @@ static void ExportIndexAlphaQuantum(const Image *image,
             {
               for (x=0; x < (ssize_t) number_pixels; x++)
               {
    -            q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
    +            q=PopShortPixel(quantum_info->endian,(unsigned short)
    +              ((ssize_t) GetPixelIndex(indexes+x)),q);
                 pixel=SinglePrecisionToHalf(QuantumScale*GetPixelAlpha(p));
                 q=PopShortPixel(quantum_info->endian,pixel,q);
                 p++;
    @@ -2762,7 +2763,8 @@ static void ExportIndexAlphaQuantum(const Image *image,
             }
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
    -        q=PopShortPixel(quantum_info->endian,(unsigned short) GetPixelIndex(indexes+x),q);
    +        q=PopShortPixel(quantum_info->endian,(unsigned short)
    +          ((ssize_t) GetPixelIndex(indexes+x)),q);
             pixel=ScaleQuantumToShort((Quantum) (QuantumRange-GetPixelOpacity(p)));
             q=PopShortPixel(quantum_info->endian,pixel,q);
             p++;
    @@ -2792,7 +2794,8 @@ static void ExportIndexAlphaQuantum(const Image *image,
             }
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
    -        q=PopLongPixel(quantum_info->endian,(unsigned int) GetPixelIndex(indexes+x),q);
    +        q=PopLongPixel(quantum_info->endian,(unsigned int)
    +          GetPixelIndex(indexes+x),q);
             pixel=ScaleQuantumToLong((Quantum) (QuantumRange-GetPixelOpacity(p)));
             q=PopLongPixel(quantum_info->endian,pixel,q);
             p++;
    @@ -2827,10 +2830,9 @@ static void ExportIndexAlphaQuantum(const Image *image,
           range=GetQuantumRange(quantum_info->depth);
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
    -        q=PopQuantumPixel(quantum_info,
    -          GetPixelIndex(indexes+x),q);
    -        q=PopQuantumPixel(quantum_info,
    -          ScaleQuantumToAny((Quantum) (GetPixelAlpha(p)),range),q);
    +        q=PopQuantumPixel(quantum_info,GetPixelIndex(indexes+x),q);
    +        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny((Quantum)
    +          (GetPixelAlpha(p)),range),q);
             p++;
             q+=quantum_info->pad;
           }
    @@ -3035,8 +3037,8 @@ static void ExportRedQuantum(QuantumInfo *quantum_info,
           range=GetQuantumRange(quantum_info->depth);
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
    -        q=PopQuantumPixel(quantum_info,
    -          ScaleQuantumToAny(GetPixelRed(p),range),q);
    +        q=PopQuantumPixel(quantum_info,ScaleQuantumToAny(GetPixelRed(p),range),
    +          q);
             p++;
             q+=quantum_info->pad;
           }
    @@ -3150,7 +3152,8 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                     break;
                   }
                 }
    -            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
    +            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
    +              q);
                 switch ((x+1) % 3)
                 {
                   default:
    @@ -3171,7 +3174,8 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                     break;
                   }
                 }
    -            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
    +            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
    +              q);
                 q+=quantum_info->pad;
               }
               for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
    @@ -3196,7 +3200,8 @@ static void ExportRGBQuantum(QuantumInfo *quantum_info,
                     break;
                   }
                 }
    -            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),q);
    +            q=PopShortPixel(quantum_info->endian,(unsigned short) (pixel << 4),
    +              q);
                 q+=quantum_info->pad;
               }
               if (bit != 0)
    
5af1dffa4b6a

outside the range of representable values of type 'unsigned char' (#3083)

https://github.com/imagemagick/imagemagickruc_zhangxiaohuiJan 6, 2021via body-scan
1 file changed · +13 13
  • MagickCore/quantum-export.c+13 13 modified
    @@ -2530,28 +2530,28 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
     
           for (x=((ssize_t) number_pixels-7); x > 0; x-=8)
           {
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q=((pixel & 0x01) << 7);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 6);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 5);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 4);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 3);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 2);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 1);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0x01) << 0);
             p+=GetPixelChannels(image);
             q++;
    @@ -2561,7 +2561,7 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
               *q='\0';
               for (bit=7; bit >= (ssize_t) (8-(number_pixels % 8)); bit--)
               {
    -            pixel=(unsigned char) GetPixelIndex(image,p);
    +            pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
                 *q|=((pixel & 0x01) << (unsigned char) bit);
                 p+=GetPixelChannels(image);
               }
    @@ -2576,17 +2576,17 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
     
           for (x=0; x < (ssize_t) (number_pixels-1) ; x+=2)
           {
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q=((pixel & 0xf) << 4);
             p+=GetPixelChannels(image);
    -        pixel=(unsigned char) GetPixelIndex(image,p);
    +        pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
             *q|=((pixel & 0xf) << 0);
             p+=GetPixelChannels(image);
             q++;
           }
           if ((number_pixels % 2) != 0)
             {
    -          pixel=(unsigned char) GetPixelIndex(image,p);
    +          pixel=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
               *q=((pixel & 0xf) << 4);
               p+=GetPixelChannels(image);
               q++;
    @@ -2597,7 +2597,7 @@ static void ExportIndexQuantum(const Image *image,QuantumInfo *quantum_info,
         {
           for (x=0; x < (ssize_t) number_pixels; x++)
           {
    -        q=PopCharPixel((unsigned char) GetPixelIndex(image,p),q);
    +        q=PopCharPixel((unsigned char) ((ssize_t) GetPixelIndex(image,p)),q);
             p+=GetPixelChannels(image);
             q+=quantum_info->pad;
           }
    

Vulnerability mechanics

Root cause

"Missing intermediate cast to `ssize_t` before truncating `GetPixelIndex()` return values to `unsigned char`, causing integer overflow when index values exceed the representable range."

Attack vector

An attacker supplies a crafted PDF file that, when processed by ImageMagick, causes `GetPixelIndex()` to return index values outside the range representable by `unsigned char` [ref_id=2]. The direct cast `(unsigned char) GetPixelIndex(...)` truncates these values, leading to undefined behavior or a crash [patch_id=2271391]. The attack requires no special privileges beyond the ability to submit a malicious PDF for ImageMagick to decode and export.

Affected code

The vulnerability resides in `ExportIndexQuantum()` and `ExportIndexAlphaQuantum()` in `MagickCore/quantum-export.c` (ImageMagick 7) and `magick/quantum-export.c` (ImageMagick 6) [patch_id=2271391][patch_id=2271393]. The functions `GetPixelIndex()` and `*indexes++` return values that are directly cast to `unsigned char` without first being cast through `ssize_t`, causing values outside the representable range of `unsigned char` to be truncated [patch_id=2271391][ref_id=2].

What the fix does

The patch inserts an intermediate cast to `ssize_t` before the final cast to `unsigned char`, e.g. `(unsigned char) ((ssize_t) GetPixelIndex(image,p))` [patch_id=2271391][patch_id=2271393]. This ensures the value is first widened to a signed type large enough to hold the full range, preventing truncation of out-of-range index values. The same pattern is applied to `ExportIndexAlphaQuantum()` and related helper calls [patch_id=2271393].

Preconditions

  • inputAttacker must supply a crafted PDF file that produces pixel index values outside the unsigned char range when processed by ImageMagick.
  • configImageMagick must be invoked to export/convert the PDF (e.g., via `convert`, `identify`, or library API), triggering the ExportIndexQuantum or ExportIndexAlphaQuantum code path.

Generated on May 24, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.