Commit 81129f79a for imagemagick.org

commit 81129f79ad622ff4c1d729828a34ab0f49ec89f6
Author: Dirk Lemstra <dirk@lemstra.org>
Date:   Fri Feb 20 14:08:15 2026 +0100

    Properly escape the strings that are written as raw html (GHSA-rw6c-xp26-225v)

diff --git a/coders/html.c b/coders/html.c
index 63eaa59fb..125796d73 100644
--- a/coders/html.c
+++ b/coders/html.c
@@ -204,6 +204,21 @@ ModuleExport void UnregisterHTMLImage(void)
 %
 */

+static void WriteHtmlEncodedString(Image *image,const char* value)
+{
+  char
+    *encoded_value;
+
+  encoded_value=AcquireString(value);
+  (void) SubstituteString(&encoded_value,"<","&lt;");
+  (void) SubstituteString(&encoded_value,">","&gt;");
+  (void) SubstituteString(&encoded_value,"&","&amp;");
+  (void) SubstituteString(&encoded_value,"\"","&quot;");
+  (void) SubstituteString(&encoded_value,"'","&apos;");
+  WriteBlobString(image,encoded_value);
+  encoded_value=DestroyString(encoded_value);
+}
+
 static ssize_t WriteURLComponent(Image *image,const int c)
 {
   char
@@ -318,29 +333,29 @@ static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
         "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
       (void) WriteBlobString(image,"<html>\n");
       (void) WriteBlobString(image,"<head>\n");
+      (void) WriteBlobString(image,"<title>");
       value=GetImageProperty(image,"label",exception);
       if (value != (const char *) NULL)
-        (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n",
-          value);
+        WriteHtmlEncodedString(image,value);
       else
         {
           GetPathComponent(filename,BasePath,basename);
-          (void) FormatLocaleString(buffer,MagickPathExtent,
-            "<title>%s</title>\n",basename);
+          WriteHtmlEncodedString(image,basename);
         }
-      (void) WriteBlobString(image,buffer);
+      (void) WriteBlobString(image,"</title>\n");
       (void) WriteBlobString(image,"</head>\n");
       (void) WriteBlobString(image,"<body style=\"text-align: center;\">\n");
-      (void) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n",
-        image->filename);
-      (void) WriteBlobString(image,buffer);
+      (void) WriteBlobString(image,"<h1>");
+      WriteHtmlEncodedString(image,image->filename);
+      (void) WriteBlobString(image,"</h1>");
       (void) WriteBlobString(image,"<div>\n");
       (void) CopyMagickString(filename,image->filename,MagickPathExtent);
       AppendImageFormat("png",filename);
-      (void) FormatLocaleString(buffer,MagickPathExtent,"<img usemap=\"#%s\" "
-        "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname,
-        filename);
-      (void) WriteBlobString(image,buffer);
+      (void) WriteBlobString(image,"<img usemap=\"#");
+      WriteHtmlEncodedString(image,mapname);
+      (void) WriteBlobString(image,"\" src=\"");
+      WriteHtmlEncodedString(image,filename);
+      (void) WriteBlobString(image,"\" style=\"border: 0;\" alt=\"Image map\" />\n");
       /*
         Determine the size and location of each image tile.
       */
@@ -350,18 +365,18 @@ static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
       /*
         Write an image map.
       */
-      (void) FormatLocaleString(buffer,MagickPathExtent,
-        "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
-      (void) WriteBlobString(image,buffer);
-      (void) FormatLocaleString(buffer,MagickPathExtent,"  <area href=\"%s",
-        url);
-      (void) WriteBlobString(image,buffer);
+      (void) WriteBlobString(image,"<map id=\"");
+      WriteHtmlEncodedString(image,mapname);
+      (void) WriteBlobString(image,"\" name=\"");
+      WriteHtmlEncodedString(image,mapname);
+      (void) WriteBlobString(image,"\">\n<area href=\"");
+      WriteHtmlEncodedString(image,url);
       if (image->directory == (char *) NULL)
         {
+          WriteHtmlEncodedString(image,image->filename);
           (void) FormatLocaleString(buffer,MagickPathExtent,
-            "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
-            image->filename,(double) geometry.width-1,(double) geometry.height-
-            1);
+            "\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
+            (double) geometry.width-1,(double) geometry.height-1);
           (void) WriteBlobString(image,buffer);
         }
       else
@@ -378,9 +393,9 @@ static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
               (void) WriteBlobString(image,buffer);
               if (*(p+1) != '\0')
                 {
-                  (void) FormatLocaleString(buffer,MagickPathExtent,
-                    "  <area href=%s\"",url);
-                  (void) WriteBlobString(image,buffer);
+                  (void) WriteBlobString(image,"  <area href=\"");
+                  WriteHtmlEncodedString(image,url);
+                  (void) WriteBlobString(image,"\"");
                 }
               geometry.x+=(ssize_t) geometry.width;
               if ((geometry.x+4) >= (ssize_t) image->columns)
@@ -390,7 +405,6 @@ static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
                 }
             }
       (void) WriteBlobString(image,"</map>\n");
-      (void) CopyMagickString(filename,image->filename,MagickPathExtent);
       (void) WriteBlobString(image,"</div>\n");
       (void) WriteBlobString(image,"</body>\n");
       (void) WriteBlobString(image,"</html>\n");
@@ -398,7 +412,6 @@ static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
       /*
         Write the image as PNG.
       */
-      (void) CopyMagickString(image->filename,filename,MagickPathExtent);
       AppendImageFormat("png",image->filename);
       next=GetNextImageInList(image);
       image->next=NewImageList();