Index: libpng-1.2.59/Makefile.am
===================================================================
--- libpng-1.2.59.orig/Makefile.am
+++ libpng-1.2.59/Makefile.am
@@ -14,10 +14,12 @@ PNGLIB_BASENAME= libpng@PNGLIB_MAJOR@@PN
 AUTOMAKE_OPTIONS = foreign
 
 # test programs - run on make check, make distcheck
-check_PROGRAMS= pngtest
+check_PROGRAMS= pngtest cve-2026-33416
 pngtest_SOURCES = pngtest.c
 pngtest_LDADD = libpng12.la
-TESTS = test-pngtest.sh
+cve_2026_33416_SOURCES = cve-2026-33416.c
+cve_2026_33416_LDADD = libpng12.la
+TESTS = test-pngtest.sh cve-2026-33416
 TESTS_ENVIRONMENT= srcdir=$(srcdir)
 
 # man pages
@@ -89,6 +91,7 @@ EXTRA_DIST= \
 	${srcdir}/contrib/pngsuite/* \
 	${srcdir}/contrib/visupng/* \
 	$(TESTS) \
+	cve-2026-33416.c \
 	example.c libpng-1.2.59.txt pnggccrd.c pngvcrd.c
 
 CLEANFILES= pngout.png libpng12.pc libpng12-config libpng.vers \
Index: libpng-1.2.59/pngread.c
===================================================================
--- libpng-1.2.59.orig/pngread.c
+++ libpng-1.2.59/pngread.c
@@ -1233,35 +1233,30 @@ png_read_destroy(png_structp png_ptr, pn
    png_free(png_ptr, png_ptr->gamma_from_1);
    png_free(png_ptr, png_ptr->gamma_to_1);
 #endif
+   png_zfree(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
 #ifdef PNG_FREE_ME_SUPPORTED
-   if (png_ptr->free_me & PNG_FREE_PLTE)
-      png_zfree(png_ptr, png_ptr->palette);
    png_ptr->free_me &= ~PNG_FREE_PLTE;
 #else
-   if (png_ptr->flags & PNG_FLAG_FREE_PLTE)
-      png_zfree(png_ptr, png_ptr->palette);
    png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
 #endif
+
 #if defined(PNG_tRNS_SUPPORTED) || \
     defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+   png_free(png_ptr, png_ptr->trans);
+   png_ptr->trans = NULL;
 #ifdef PNG_FREE_ME_SUPPORTED
-   if (png_ptr->free_me & PNG_FREE_TRNS)
-      png_free(png_ptr, png_ptr->trans);
    png_ptr->free_me &= ~PNG_FREE_TRNS;
 #else
-   if (png_ptr->flags & PNG_FLAG_FREE_TRNS)
-      png_free(png_ptr, png_ptr->trans);
    png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
 #endif
 #endif
 #ifdef PNG_READ_hIST_SUPPORTED
+   png_free(png_ptr, png_ptr->hist);
+   png_ptr->hist = NULL;
 #ifdef PNG_FREE_ME_SUPPORTED
-   if (png_ptr->free_me & PNG_FREE_HIST)
-      png_free(png_ptr, png_ptr->hist);
    png_ptr->free_me &= ~PNG_FREE_HIST;
 #else
-   if (png_ptr->flags & PNG_FLAG_FREE_HIST)
-      png_free(png_ptr, png_ptr->hist);
    png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
 #endif
 #endif
Index: libpng-1.2.59/pngrtran.c
===================================================================
--- libpng-1.2.59.orig/pngrtran.c
+++ libpng-1.2.59/pngrtran.c
@@ -471,7 +471,13 @@ png_set_dither(png_structp png_ptr, png_
    }
    if (png_ptr->palette == NULL)
    {
-      png_ptr->palette = palette;
+      /* Allocate an owned copy rather than aliasing the caller's pointer,
+       * so that png_read_destroy can free png_ptr->palette unconditionally.
+       */
+      png_ptr->palette = (png_colorp)png_calloc(png_ptr,
+        PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
+      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
    }
    png_ptr->num_palette = (png_uint_16)num_palette;
 
@@ -1208,6 +1214,21 @@ png_read_transform_info(png_structp png_
 {
    png_debug(1, "in png_read_transform_info");
 
+   if (png_ptr->transformations != 0)
+   {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+          info_ptr->palette != NULL && png_ptr->palette != NULL)
+      {
+         /* Sync info_ptr->palette with png_ptr->palette.
+          * The function png_init_read_transformations may have modified
+          * png_ptr->palette in place (e.g. for gamma correction or for
+          * background compositing).
+          */
+         png_memcpy(info_ptr->palette, png_ptr->palette,
+         PNG_MAX_PALETTE_LENGTH * (png_sizeof(png_color)));
+      }
+   }
+
 #ifdef PNG_READ_EXPAND_SUPPORTED
    if (png_ptr->transformations & PNG_EXPAND)
    {
Index: libpng-1.2.59/pngset.c
===================================================================
--- libpng-1.2.59.orig/pngset.c
+++ libpng-1.2.59/pngset.c
@@ -200,9 +200,11 @@ png_set_hIST(png_structp png_ptr, png_in
 #ifdef PNG_FREE_ME_SUPPORTED
    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
 #endif
+
    /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
     * version 1.2.1
     */
+   png_free(png_ptr, png_ptr->hist);
    png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr,
       (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)));
    if (png_ptr->hist == NULL)
@@ -211,11 +213,19 @@ png_set_hIST(png_structp png_ptr, png_in
       return;
    }
 
+   info_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr,
+      (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)));
+   if (info_ptr->hist == NULL)
+   {
+      png_free(png_ptr, png_ptr->hist);
+      png_ptr->hist = NULL;
+      png_warning(png_ptr, "Insufficient memory for hIST chunk data.");
+      return;
+   }
+
    for (i = 0; i < info_ptr->num_palette; i++)
-      png_ptr->hist[i] = hist[i];
-   info_ptr->hist = png_ptr->hist;
+      png_ptr->hist[i] = info_ptr->hist[i] = hist[i];
    info_ptr->valid |= PNG_INFO_hIST;
-
 #ifdef PNG_FREE_ME_SUPPORTED
    info_ptr->free_me |= PNG_FREE_HIST;
 #else
@@ -224,6 +234,7 @@ png_set_hIST(png_structp png_ptr, png_in
 }
 #endif
 
+
 void PNGAPI
 png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
    png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -483,10 +494,17 @@ png_set_PLTE(png_structp png_ptr, png_in
     * of num_palette entries, in case of an invalid PNG file or incorrect
     * call to png_set_PLTE() with too-large sample values.
     */
+
+   /* Always separate png_ptr->palette from info_ptr->palette */
+   png_free(png_ptr, png_ptr->palette);
    png_ptr->palette = (png_colorp)png_calloc(png_ptr,
       PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
    png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color));
-   info_ptr->palette = png_ptr->palette;
+
+   info_ptr->palette = (png_colorp)png_calloc(png_ptr,
+      PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
+   png_memcpy(info_ptr->palette, palette, num_palette * png_sizeof(png_color));
+
    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
 
 #ifdef PNG_FREE_ME_SUPPORTED
@@ -896,10 +914,20 @@ png_set_tRNS(png_structp png_ptr, png_in
 #endif
 
        /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
-       png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr,
+       png_free(png_ptr, png_ptr->trans);
+       png_ptr->trans = (png_bytep)png_malloc(png_ptr,
+           (png_uint_32)PNG_MAX_PALETTE_LENGTH);
+       info_ptr->trans = (png_bytep)png_malloc(png_ptr,
            (png_uint_32)PNG_MAX_PALETTE_LENGTH);
+
+       png_memset(png_ptr->trans, 0xff, PNG_MAX_PALETTE_LENGTH);
+       png_memset(info_ptr->trans, 0xff, PNG_MAX_PALETTE_LENGTH);
+
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+       {
+          png_memcpy(png_ptr->trans, trans, (png_size_t)num_trans);
           png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans);
+       }
    }
 
    if (trans_values != NULL)
Index: libpng-1.2.59/pngwrite.c
===================================================================
--- libpng-1.2.59.orig/pngwrite.c
+++ libpng-1.2.59/pngwrite.c
@@ -1129,6 +1129,16 @@ png_write_destroy(png_structp png_ptr)
    /* Free our memory.  png_free checks NULL for us. */
    png_free(png_ptr, png_ptr->zbuf);
    png_free(png_ptr, png_ptr->row_buf);
+   png_zfree(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
+#ifdef PNG_WRITE_tRNS_SUPPORTED
+   png_free(png_ptr, png_ptr->trans);
+   png_ptr->trans = NULL;
+#endif
+#ifdef PNG_WRITE_hIST_SUPPORTED
+   png_free(png_ptr, png_ptr->hist);
+   png_ptr->hist = NULL;
+#endif
 #ifdef PNG_WRITE_FILTER_SUPPORTED
    png_free(png_ptr, png_ptr->prev_row);
    png_free(png_ptr, png_ptr->sub_row);
Index: libpng-1.2.59/cve-2026-33416.c
===================================================================
--- /dev/null
+++ libpng-1.2.59/cve-2026-33416.c
@@ -0,0 +1,196 @@
+#include "png.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Test case for CVE-2026-33416: Use-after-free in png_set_PLTE, png_set_tRNS, png_set_hIST.
+ * This test verifies that info_ptr and png_ptr buffers are decoupled and
+ * that calling setter functions multiple times does not lead to leaks or UAF.
+ */
+
+static int test_PLTE(void) {
+    printf("Testing PLTE decoupling...\n");
+    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr) return 1;
+    png_infop info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        return 1;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        return 1;
+    }
+
+    png_color palette[1];
+    palette[0].red = 100; palette[0].green = 150; palette[0].blue = 200;
+
+    // First set
+    png_set_PLTE(png_ptr, info_ptr, palette, 1);
+    if (info_ptr->palette == png_ptr->palette) {
+        fprintf(stderr, "FAIL: PLTE pointers are aliased after first set\n");
+        goto fail;
+    }
+
+    // Second set (should free old png_ptr->palette and info_ptr->palette)
+    palette[0].red = 255;
+    png_set_PLTE(png_ptr, info_ptr, palette, 1);
+    if (info_ptr->palette == png_ptr->palette) {
+        fprintf(stderr, "FAIL: PLTE pointers are aliased after second set\n");
+        goto fail;
+    }
+
+    // Verify independent freeing
+    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1);
+    if (info_ptr->palette != NULL) {
+        fprintf(stderr, "FAIL: info_ptr->palette not NULL after free\n");
+        goto fail;
+    }
+    if (png_ptr->palette == NULL) {
+        fprintf(stderr, "FAIL: png_ptr->palette incorrectly NULL after info_ptr free\n");
+        goto fail;
+    }
+    if (png_ptr->palette[0].red != 255) {
+        fprintf(stderr, "FAIL: png_ptr->palette data corrupted after info_ptr free\n");
+        goto fail;
+    }
+
+    printf("PASS: PLTE\n");
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 0;
+
+fail:
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 1;
+}
+
+static int test_tRNS(void) {
+    printf("Testing tRNS decoupling...\n");
+    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr) return 1;
+    png_infop info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        return 1;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        return 1;
+    }
+
+    png_byte trans[1] = {123};
+
+    // First set
+    png_set_tRNS(png_ptr, info_ptr, trans, 1, NULL);
+    if (info_ptr->trans == png_ptr->trans) {
+        fprintf(stderr, "FAIL: tRNS pointers are aliased after first set\n");
+        goto fail;
+    }
+
+    // Second set
+    trans[0] = 200;
+    png_set_tRNS(png_ptr, info_ptr, trans, 1, NULL);
+    if (info_ptr->trans == png_ptr->trans) {
+        fprintf(stderr, "FAIL: tRNS pointers are aliased after second set\n");
+        goto fail;
+    }
+
+    // Verify independent freeing
+    png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
+    if (info_ptr->trans != NULL) {
+        fprintf(stderr, "FAIL: info_ptr->trans not NULL after free\n");
+        goto fail;
+    }
+    if (png_ptr->trans == NULL) {
+        fprintf(stderr, "FAIL: png_ptr->trans incorrectly NULL after info_ptr free\n");
+        goto fail;
+    }
+    if (png_ptr->trans[0] != 200) {
+        fprintf(stderr, "FAIL: png_ptr->trans data corrupted after info_ptr free\n");
+        goto fail;
+    }
+
+    printf("PASS: tRNS\n");
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 0;
+
+fail:
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 1;
+}
+
+static int test_hIST(void) {
+    printf("Testing hIST decoupling...\n");
+    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_ptr) return 1;
+    png_infop info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, NULL, NULL);
+        return 1;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr))) {
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        return 1;
+    }
+
+    // Must set palette before hIST in libpng-1.2
+    png_color palette[1] = {{0,0,0}};
+    png_set_PLTE(png_ptr, info_ptr, palette, 1);
+
+    png_uint_16 hist[1] = {500};
+
+    // First set
+    png_set_hIST(png_ptr, info_ptr, hist);
+    if (info_ptr->hist == png_ptr->hist) {
+        fprintf(stderr, "FAIL: hIST pointers are aliased after first set\n");
+        goto fail;
+    }
+
+    // Second set
+    hist[0] = 1000;
+    png_set_hIST(png_ptr, info_ptr, hist);
+    if (info_ptr->hist == png_ptr->hist) {
+        fprintf(stderr, "FAIL: hIST pointers are aliased after second set\n");
+        goto fail;
+    }
+
+    // Verify independent freeing
+    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1);
+    if (info_ptr->hist != NULL) {
+        fprintf(stderr, "FAIL: info_ptr->hist not NULL after free\n");
+        goto fail;
+    }
+    if (png_ptr->hist == NULL) {
+        fprintf(stderr, "FAIL: png_ptr->hist incorrectly NULL after info_ptr free\n");
+        goto fail;
+    }
+    if (png_ptr->hist[0] != 1000) {
+        fprintf(stderr, "FAIL: png_ptr->hist data corrupted after info_ptr free\n");
+        goto fail;
+    }
+
+    printf("PASS: hIST\n");
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 0;
+
+fail:
+    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    return 1;
+}
+
+int main(void) {
+    int count = 0;
+    count += test_PLTE();
+    count += test_tRNS();
+    count += test_hIST();
+    if (count == 0) {
+        printf("ALL TESTS PASSED\n");
+        return 0;
+    }
+    printf("%d TESTS FAILED\n", count);
+    return 1;
+}
