PyPI / pillow / 13.0.0

pillow 13.0.0

Source
https://github.com/python-pillow/Pillow
Tag scanned
13.0.0
Compared with
12.3.0 (4 signals introduced since)
Files
600 scanned, 1156 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 61 info
Scan time
36.6 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 56 of 56 warn and critical signals; 56 demoted to info.
Disclude version
4.1.0
Scanned (UTC)
2026-10-21 22:59

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info warn → info by review encoding-base64 Tests/test_file_libtiff.py:1490:19 new in this release

    base64-like blob (56 bytes, compression ratio 1.20) (raw pass, confidence 0.60)

                    b"rq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna"
                    b"29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+foAAQIDBJ9Bepo="
                ),
                # 16x16 strip with duplicated
    likely benign LLM, confidence 0.93 Base64-encoded test image bytes in a libtiff test.
    Reasoning

    Base64 blob inside a test fixture for a TIFF image; it is raw image data in a test, a common pattern.

  2. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:248:9 new in this release

    two identifiers collapse to visual skeleton `y|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        int x1,
        int y1,
        int ink,
        point_handler point,
    dismissed LLM, confidence 0.93 Parameter name y1 flagged by the confusable heuristic.
    Reasoning

    Standard coordinate parameter naming in a line-drawing function; no homoglyph or hidden characters.

  3. info warn → info by review identifier-confusable-collision src/libImaging/Mode.c:150:6 new in this release

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_L_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        [IMAGING_RAWMODE_L_16B] = {"L;16B"},
        [IMAGING_RAWMODE_L_1] = {"L;1"},
        [IMAGING_RAWMODE_L_2] = {"L;2"},
        [IMAGING_RAWMODE_L_2I] = {"L;2I"},
    dismissed LLM, confidence 0.93 Pillow rawmode table entries for L-mode formats with confusable-looking suffixes.
    Reasoning

    IMAGING_RAWMODE_L_1 and IMAGING_RAWMODE_L_2I are ordinary enum names mapping to format strings such as L;1 and L;2I. The collision is a naming artifact of Pillow's mode-table conventions, and the code is a plain data table.

  4. info warn → info by review identifier-confusable-collision src/libImaging/Mode.h:148:5 new in this release

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_L_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        IMAGING_RAWMODE_LX,
        IMAGING_RAWMODE_L_1,
        IMAGING_RAWMODE_L_16,
        IMAGING_RAWMODE_L_16B,
    dismissed LLM, confidence 0.93 Pillow header enum entries for L-mode rawmode variants.
    Reasoning

    These are ordinary enum members for L-mode rawmodes, with a comment-free declaration list typical of a C header. No executable or hidden behaviour is present.

  5. info warn → info by review payload-bytes-literal Tests/test_file_tiff_metadata.py:437:9

    concatenated bytes literal contains 48 `\xNN` escapes (95% of content) — binary payload shape (ast pass, confidence 0.85)

        data = io.BytesIO(
            b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
            b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a "
    likely benign LLM, confidence 0.90 Hand-built TIFF byte fixture in a metadata test.
    Reasoning

    Bytes literal with \x escapes is a TIFF file header built in-memory for a metadata test, expected for binary format testing.

  6. info warn → info by review payload-bytes-literal Tests/test_pickle.py:170:9

    concatenated bytes literal contains 32 `\xNN` escapes (75% of content) — binary payload shape (ast pass, confidence 0.85)

        im = pickle.loads(
            b"\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00\x8c\x12PIL.PngImagePlugin"
            b"\x94\x8c\x0cPngImageFile\x94\x93\x94)\x81\x94]\x94(}\x94\x8c\x01L\x94K\x01"
            b"K\x01\x86\x94NC\x01\x00\x94eb."
    likely benign LLM, confidence 0.90 Serialized pickle fixture for a PIL PngImageFile in a test.
    Reasoning

    Pickle bytes for a PNG image plugin used in a pickle round-trip test; a fixed literal, not attacker-controlled at runtime, consistent with testing pickling of PIL objects.

  7. info dynamic-execution depends/install_libavif.sh:32:8

    command name is a variable (`$PKGCONFIG`) that this file sets only to plain text (ast pass, confidence 0.40)

    
        if $PKGCONFIG --exists aom; then
            LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=SYSTEM)
            HAS_ENCODER=1
  8. info dynamic-execution depends/install_libavif.sh:38:8

    command name is a variable (`$PKGCONFIG`) that this file sets only to plain text (ast pass, confidence 0.40)

    
        if $PKGCONFIG --exists dav1d; then
            LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_DAV1D=SYSTEM)
            HAS_DECODER=1
  9. info dynamic-execution depends/install_libavif.sh:43:8

    command name is a variable (`$PKGCONFIG`) that this file sets only to plain text (ast pass, confidence 0.40)

    
        if $PKGCONFIG --exists libgav1; then
            LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_LIBGAV1=SYSTEM)
            HAS_DECODER=1
  10. info dynamic-execution depends/install_libavif.sh:48:8

    command name is a variable (`$PKGCONFIG`) that this file sets only to plain text (ast pass, confidence 0.40)

    
        if $PKGCONFIG --exists rav1e; then
            LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_RAV1E=SYSTEM)
            HAS_ENCODER=1
  11. info dynamic-execution depends/install_libavif.sh:53:8

    command name is a variable (`$PKGCONFIG`) that this file sets only to plain text (ast pass, confidence 0.40)

    
        if $PKGCONFIG --exists SvtAv1Enc; then
            LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_SVT=SYSTEM)
            HAS_ENCODER=1
  12. info warn → info by review dynamic-attribute setup.py:523:20

    reach-by-name through `globals` (ast pass, confidence 0.60)

            }.items():
                root = globals()[root_name]
    
                if root is None and root_name in os.environ:
    likely benign LLM, confidence 0.85 globals() lookup in setup.py to find a dependency root.
    Reasoning

    Looking up a root object by name in globals() in setup.py is a configuration-discovery pattern for locating optional dependencies; low risk in a build script but worth a glance.

  13. info warn → info by review dynamic-attribute src/PIL/BmpImagePlugin.py:80:9

    reach-by-name through `vars` (ast pass, confidence 0.60)

        for k, v in COMPRESSIONS.items():
            vars()[k] = v
    
        def _bitmap(self, header: int = 0, offset: int = 0) -> None:
    likely benign LLM, confidence 0.88 Dynamic assignment of compression constants into module namespace.
    Reasoning

    Populates module attributes from a compression dictionary via vars(); a standard way to define constants dynamically, with fixed keys.

  14. info warn → info by review encoding-base64 src/PIL/ImageFont.py:1066:1

    base64-like blob (1700 bytes over 23 lines, compression ratio 0.70) (raw pass, confidence 0.60)

            Image.open(BytesIO(base64.b64decode(b"""
    iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u
    Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9
    M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g
    likely benign LLM, confidence 0.90 Embedded base64 PNG sample in ImageFont documentation.
    Reasoning

    Base64 blob inside a docstring or doctest showing an embedded PNG image; a documentation/test artifact, not executed.

  15. info warn → info by review dynamic-execution src/PIL/ImageMath.py:297:21

    `compile` called on a non-literal expression (ast pass, confidence 0.70)

    
        compiled_code = compile(expression, "<string>", "eval")
    
        def scan(code: CodeType) -> None:
    likely benign LLM, confidence 0.80 compile() of an expression for the ImageMath evaluator.
    Reasoning

    ImageMath compiles user-supplied expression strings for its documented eval-style math API; intended but a real dynamic-execution surface, though restricted by a scanning step.

  16. info critical → info by review dynamic-execution src/PIL/ImageShow.py:125:9

    `os.system` called on a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

                raise FileNotFoundError
            os.system(self.get_command(path, **options))  # nosec
            return 1
    likely benign LLM, confidence 0.75 os.system call launching an external image viewer.
    Reasoning

    Runs a viewer command built from get_command at runtime, with a nosec marker; the command comes from the library's own viewer configuration and file path, which is expected for an image viewer, though it is a shell invocation with variable input.

  17. info warn → info by review decoder-decompress-payload src/PIL/PdfParser.py:337:20

    file imports decoder module(s) codecs, zlib and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

            if filter == b"FlateDecode":
                dobj = zlib.decompressobj()
                plaintext = dobj.decompress(self.buf, max_length)
                if dobj.unconsumed_tail:
    likely benign LLM, confidence 0.85 FlateDecode stream decompression in the PDF parser.
    Reasoning

    zlib decompression of PDF FlateDecode streams is the core function of a PDF parser; processing input data, not hidden payload execution.

  18. info warn → info by review encoding-octal src/PIL/PdfParser.py:645:37

    6 consecutive `\NNN` octal escapes (entropy 2.6 bits/byte) (raw pass, confidence 0.65)

        delimiter = rb"[][()<>{}/%]"
        delimiter_or_ws = rb"[][()<>{}/%\000\011\012\014\015\040]"
        whitespace = rb"[\000\011\012\014\015\040]"
        whitespace_or_hex = rb"[\000\011\012\014\015\0400-9a-fA-F]"
    likely benign LLM, confidence 0.90 Regex character classes for PDF whitespace and delimiters.
    Reasoning

    Octal escapes in regex character classes for PDF whitespace and delimiters; standard PDF syntax definitions.

  19. info warn → info by review encoding-octal src/PIL/PdfParser.py:646:22

    6 consecutive `\NNN` octal escapes (entropy 2.6 bits/byte) (raw pass, confidence 0.65)

        delimiter_or_ws = rb"[][()<>{}/%\000\011\012\014\015\040]"
        whitespace = rb"[\000\011\012\014\015\040]"
        whitespace_or_hex = rb"[\000\011\012\014\015\0400-9a-fA-F]"
        whitespace_optional = whitespace + b"*"
    likely benign LLM, confidence 0.90 Regex character class for PDF whitespace and hex characters.
    Reasoning

    Same PDF whitespace regex character class definitions as neighboring lines; legitimate.

  20. info warn → info by review encoding-octal src/PIL/PdfParser.py:647:29

    6 consecutive `\NNN` octal escapes (entropy 2.6 bits/byte) (raw pass, confidence 0.65)

        whitespace = rb"[\000\011\012\014\015\040]"
        whitespace_or_hex = rb"[\000\011\012\014\015\0400-9a-fA-F]"
        whitespace_optional = whitespace + b"*"
        whitespace_mandatory = whitespace + b"+"
    likely benign LLM, confidence 0.90 PDF whitespace regex constant definitions.
    Reasoning

    PDF whitespace regex definitions with octal escapes; legitimate parser constants.

  21. info warn → info by review decoder-decompress-payload src/PIL/PngImagePlugin.py:155:12

    file imports decoder module(s) zlib and calls `.decompress()` — embedded payload decompressed at runtime (ast pass, confidence 0.75)

    def _safe_zlib_decompress(s: bytes) -> bytes:
        dobj = zlib.decompressobj()
        plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
        if dobj.unconsumed_tail:
    likely benign LLM, confidence 0.85 Size-limited zlib decompression for PNG text chunks.
    Reasoning

    Bounded zlib decompression of PNG text chunks with MAX_TEXT_CHUNK limit, a safe-decompression helper; standard PNG handling.

  22. info warn → info by review payload-bytes-literal src/PIL/WalImageFile.py:86:5

    concatenated bytes literal contains 768 `\xNN` escapes (100% of content) — binary payload shape (ast pass, confidence 0.85)

        # default palette taken from piffo 0.93 by Hans Häggström
        b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
        b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
        b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
    likely benign LLM, confidence 0.93 Default colour palette for the WAL image format, embedded as a bytes literal.
    Reasoning

    The bytes literal is a 256-entry RGB palette (three bytes per colour, ramping smoothly) and the comment credits its source. Palette data written as escapes is a normal way to embed constants in an image-format decoder, so this is not an obfuscated payload.

  23. info warn → info by review encoding-hex src/PIL/WalImageFile.py:89:7

    16 consecutive `\xNN` escapes (entropy 3.6 bits/byte) (raw pass, confidence 0.65)

        b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
        b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b"
        b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10"
        b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07"
    likely benign LLM, confidence 0.92 Continuation of the WAL default palette byte table.
    Reasoning

    This is a continuation of the same palette table. The values are monotonic-ish colour components with no decoding step, so the raw entropy signal reflects ordinary image data.

  24. info warn → info by review encoding-hex src/PIL/WalImageFile.py:95:7

    5 rows of escape runs, lines 95-101 (first: 16 consecutive `\xNN` escapes (entropy 4.0 bits/byte)) (raw pass, confidence 0.65)

        b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d"
        b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31"
        b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28"
        b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07"
    likely benign LLM, confidence 0.92 Further rows of the WAL palette constant.
    Reasoning

    Same palette byte table in the same file; the escape runs are constant data consumed directly as bytes, with no execution or decoding path.

  25. info warn → info by review encoding-hex src/PIL/WalImageFile.py:105:7

    16 consecutive `\xNN` escapes (entropy 3.6 bits/byte) (raw pass, confidence 0.65)

        b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14"
        b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f"
        b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
        b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
    likely benign LLM, confidence 0.92 More rows of the WAL palette constant.
    Reasoning

    Continuation of the static palette literal. Nothing in the snippet decodes or executes these bytes.

  26. info warn → info by review encoding-hex src/PIL/WalImageFile.py:107:7

    16 consecutive `\xNN` escapes (entropy 4.0 bits/byte) (raw pass, confidence 0.65)

        b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
        b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
        b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14"
        b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01"
    likely benign LLM, confidence 0.92 Palette rows in the WAL default colour table.
    Reasoning

    Another static palette row. The byte values are plain colour data, consistent with a legitimate image format default.

  27. info warn → info by review encoding-hex src/PIL/WalImageFile.py:113:7

    8 rows of escape runs, lines 113-125 (first: 16 consecutive `\xNN` escapes (entropy 3.5 bits/byte)) (raw pass, confidence 0.65)

        b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01"
        b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27"
        b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c"
        b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a"
    likely benign LLM, confidence 0.92 Palette rows of the WAL colour table.
    Reasoning

    Static palette data that is part of the same literal. No dynamic behaviour appears in the snippet.

  28. info warn → info by review encoding-hex src/PIL/WalImageFile.py:132:7

    16 consecutive `\xNN` escapes (entropy 3.9 bits/byte) (raw pass, confidence 0.65)

        b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
        b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
        b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
    )
    likely benign LLM, confidence 0.92 Final rows of the WAL default palette.
    Reasoning

    Closing rows of the same palette literal, which is a plain constant in an image decoder.

  29. info warn → info by review encoding-hex src/PIL/WalImageFile.py:133:7

    16 consecutive `\xNN` escapes (entropy 3.9 bits/byte) (raw pass, confidence 0.65)

        b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
        b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
    )
    likely benign LLM, confidence 0.92 Tail of the WAL palette literal.
    Reasoning

    Last palette row; the literal is static data and the file is a standard Pillow image plugin.

  30. info critical → info by review dynamic-import src/PIL/features.py:42:9

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

        try:
            __import__(module)
            return True
        except ModuleNotFoundError:
    dismissed LLM, confidence 0.90 Availability check that imports an optional dependency by name.
    Reasoning

    Pillow's feature-check helper imports an optional module by name to test whether it is installed, catching ModuleNotFoundError. The module name comes from internal callers with fixed names, so this is a standard availability probe.

  31. info critical → info by review dynamic-import src/PIL/features.py:63:20

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

    
        return getattr(__import__(module, fromlist=[ver]), ver)
    dismissed LLM, confidence 0.90 Fetches the version of an optional library for feature reporting.
    Reasoning

    Reads a module's version attribute via __import__ with a fixed fromlist. This is a version-reporting helper for optional libraries, not a hidden execution path.

  32. info critical → info by review dynamic-import src/PIL/features.py:153:27

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

        try:
            imported_module = __import__(module, fromlist=["PIL"])
            return getattr(imported_module, flag)
        except ModuleNotFoundError:
    dismissed LLM, confidence 0.90 Internal feature-flag lookup through a dynamic import.
    Reasoning

    Imports the PIL package's internal module and retrieves a flag attribute, guarded by ModuleNotFoundError. This is internal feature detection in a well-known library.

  33. info critical → info by review dynamic-import src/PIL/features.py:176:20

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

    
        return getattr(__import__(module, fromlist=[ver]), ver)
    dismissed LLM, confidence 0.90 Version lookup for an optional dependency.
    Reasoning

    Same version-lookup helper pattern as earlier in the file, applied to optional modules. Benign.

  34. info warn → info by review dynamic-attribute src/Tk/tkImaging.c:387:12

    `dlsym` called with a non-literal symbol name (ast pass, confidence 0.75)

        dlerror();
        func = dlsym(lib_handle, func_name);
        if (func == NULL) {
            const char *error = dlerror();
    likely benign LLM, confidence 0.88 Runtime symbol resolution for Tk functions in the imaging extension.
    Reasoning

    Pillow's Tk bridge resolves Tk and Tcl entry points at runtime with dlsym so it can work against whichever Tk library is loaded. The symbol names are fixed internal names, which is a standard way to bind optional shared-library functions.

  35. info warn → info by review dynamic-import src/Tk/tkImaging.c:436:20

    `dlopen` called with a non-literal path (ast pass, confidence 0.75)

        /* Try loading from the main program namespace first */
        main_program = dlopen(NULL, RTLD_LAZY);
        if (_func_loader(main_program) == 0) {
            dlclose(main_program);
    likely benign LLM, confidence 0.88 Loads Tk symbols from the main program or a Tk shared library.
    Reasoning

    Opens the main program's namespace with dlopen(NULL), then falls back to loading the Tk library. This is a common pattern for locating Tk symbols at runtime and the path is not attacker-controlled in this snippet.

  36. info warn → info by review dynamic-import src/Tk/tkImaging.c:462:19

    `dlopen` called with a non-literal path (ast pass, confidence 0.75)

        }
        tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY);
        if (tkinter_lib == NULL) {
            PyErr_SetString(PyExc_RuntimeError, "Cannot dlopen tkinter module file");
    likely benign LLM, confidence 0.85 dlopen of the tkinter library at a runtime-computed path in Pillow's Tk imaging code.
    Reasoning

    This is the Pillow Tk integration loading the tkinter shared library by a computed filename via dlopen, a common pattern for locating a platform-specific extension module. The path is derived from the Python installation, not attacker-controlled input in the snippet, so it is a legitimate dynamic load.

  37. info warn → info by review identifier-confusable-collision src/libImaging/Access.c:101:6

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    static struct ImagingAccessInstance accessors[] = {
        {IMAGING_MODE_1, get_pixel_8, put_pixel_8},
        {IMAGING_MODE_L, get_pixel_8, put_pixel_8},
        {IMAGING_MODE_LA, get_pixel_32_2bands, put_pixel_32},
    dismissed LLM, confidence 0.95 Ordinary Pillow mode-constant names that the confusable heuristic flags due to 0/O and 1/l/I similarity.
    Reasoning

    Identifiers like IMAGING_MODE_1 and IMAGING_MODE_L differ only in ordinary characters; the skeleton collision reflects the normal use of uppercase names like MODE and digits in C macros. No invisible or homoglyph characters are involved, so this is a false positive from the token heuristic.

  38. info warn → info by review identifier-confusable-collision src/libImaging/Convert.c:1068:17

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        if (mode == IMAGING_MODE_1) {
            convert = alpha ? pa2bit : p2bit;
        } else if (mode == IMAGING_MODE_L) {
    dismissed LLM, confidence 0.95 Mode constant comparisons flagged by the confusable-identifier heuristic.
    Reasoning

    Standard IMAGING_MODE_1 and IMAGING_MODE_L constant comparisons; the skeleton collision is an artifact of uppercase letters and digit 1 in ASCII names.

  39. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:82:9

    two identifiers collapse to visual skeleton `xo` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        int d;
        int x0, y0;
        int xmin, ymin, xmax, ymax;
        float dx;
    dismissed LLM, confidence 0.95 Coordinate variables xo and yo flagged by the confusable heuristic.
    Reasoning

    Plain variable names xo and yo in a drawing routine; the collision comes from lowercase o being treated as confusable with 0. Ordinary coordinate naming.

  40. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:82:13

    two identifiers collapse to visual skeleton `yo` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        int d;
        int x0, y0;
        int xmin, ymin, xmax, ymax;
        float dx;
    dismissed LLM, confidence 0.95 Variable yo flagged by the confusable heuristic.
    Reasoning

    Same as the other xo/yo case; ordinary coordinate identifier naming in a graphics routine.

  41. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:127:40

    two identifiers collapse to visual skeleton `x|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    static inline void
    hline8(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
        if (y0 >= 0 && y0 < im->ysize) {
            if (x0 < 0) {
    dismissed LLM, confidence 0.93 Coordinate parameter name in hline8 flagged by the confusable heuristic.
    Reasoning

    Parameter names x0/y0 and x1 in a horizontal line routine; the collision is a generic artifact of digit and letter similarity.

  42. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:937:20

    two identifiers collapse to visual skeleton `c|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        int32_t py, pl, pr;
        int32_t cy[4], cl[4], cr[4];
        int8_t bufcnt;
        int8_t finished;
    dismissed LLM, confidence 0.93 Array identifier cy flagged by the confusable heuristic.
    Reasoning

    Ordinary array identifiers cy/cl/cr in a drawing routine; the collision is a heuristic false positive.

  43. info warn → info by review identifier-confusable-collision src/libImaging/Draw.c:1202:25

    two identifiers collapse to visual skeleton `a|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    void
    normalize_angles(float *al, float *ar) {
        if (*ar - *al >= 360) {
            *al = 0;
    dismissed LLM, confidence 0.93 Angle parameter al flagged by the confusable heuristic.
    Reasoning

    Parameter names al/ar in normalize_angles are ordinary; the skeleton match is spurious.

  44. info warn → info by review identifier-confusable-collision src/libImaging/Fill.c:87:17

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        if (mode != IMAGING_MODE_1 && mode != IMAGING_MODE_F && mode != IMAGING_MODE_I &&
            mode != IMAGING_MODE_L && mode != IMAGING_MODE_P) {
            return (Imaging)ImagingError_ModeError();
    dismissed LLM, confidence 0.95 Mode constant comparisons flagged by the confusable heuristic.
    Reasoning

    Standard IMAGING_MODE constant comparisons in a mode check; no confusable homoglyphs present.

  45. info warn → info by review identifier-confusable-collision src/libImaging/Geometry.c:800:9

    two identifiers collapse to visual skeleton `xo` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        Imaging imIn,
        int x0,
        int y0,
        int x1,
    dismissed LLM, confidence 0.93 Coordinate parameter xo flagged by the confusable heuristic.
    Reasoning

    Ordinary coordinate parameters x0 and x1 in a geometry function; false positive from digit/letter similarity.

  46. info warn → info by review identifier-confusable-collision src/libImaging/Geometry.c:801:9

    two identifiers collapse to visual skeleton `yo` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        int x0,
        int y0,
        int x1,
        int y1,
    dismissed LLM, confidence 0.93 Coordinate parameter yo flagged by the confusable heuristic.
    Reasoning

    Ordinary coordinate parameters y0 and y1 in a geometry function; false positive.

  47. info warn → info by review macro-keyword-override src/libImaging/ImPlatform.h:52:1

    `#define FLOAT32 float` aliases a C reserved keyword behind a non-keyword macro name (ast pass, confidence 0.85)

    #define FLOAT16 UINT16
    #define FLOAT32 float
    #define FLOAT64 double
    likely benign LLM, confidence 0.90 Portable type alias macro for float in Pillow's platform header.
    Reasoning

    Pillow's ImPlatform.h defines portable FLOAT32 and FLOAT64 type aliases to float and double; this is a standard typedef-style macro for cross-platform sized types, not malicious.

  48. info warn → info by review macro-keyword-override src/libImaging/ImPlatform.h:53:1

    `#define FLOAT64 double` aliases a C reserved keyword behind a non-keyword macro name (ast pass, confidence 0.85)

    #define FLOAT32 float
    #define FLOAT64 double
    
    #ifdef _MSC_VER
    likely benign LLM, confidence 0.90 Portable type alias macro for double in Pillow's platform header.
    Reasoning

    Same portable FLOAT64 alias to double in the platform header; legitimate type portability definition.

  49. info warn → info by review identifier-confusable-collision src/libImaging/Mode.c:7:6

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        [IMAGING_MODE_1] = {"1"},         [IMAGING_MODE_CMYK] = {"CMYK"},
        [IMAGING_MODE_F] = {"F"},         [IMAGING_MODE_HSV] = {"HSV"},
        [IMAGING_MODE_I] = {"I"},         [IMAGING_MODE_L] = {"L"},
    dismissed LLM, confidence 0.95 Mode name lookup table flagged by the confusable heuristic.
    Reasoning

    Mode name table entries using IMAGING_MODE constants; the skeleton collision is a heuristic artifact of the uppercase names.

  50. info warn → info by review identifier-confusable-collision src/libImaging/Mode.c:44:6

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        [IMAGING_RAWMODE_1] = {"1"},
        [IMAGING_RAWMODE_CMYK] = {"CMYK"},
        [IMAGING_RAWMODE_F] = {"F"},
    dismissed LLM, confidence 0.95 Raw mode name table flagged by the confusable heuristic.
    Reasoning

    Raw-mode name table using IMAGING_RAWMODE constants; the collision is a heuristic false positive from ordinary ASCII identifiers.

  51. info warn → info by review identifier-confusable-collision src/libImaging/Mode.c:70:6

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|_8` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        [IMAGING_RAWMODE_1_8] = {"1;8"},
        [IMAGING_RAWMODE_1_I] = {"1;I"},
        [IMAGING_RAWMODE_1_IR] = {"1;IR"},
    dismissed LLM, confidence 0.93 Pillow rawmode table entries for 1-bit pixel formats whose names differ only in confusable characters.
    Reasoning

    The two identifiers are distinct, legitimately named rawmode enum entries (1;8 and 1;I) in Pillow's pixel-mode table. Their visual similarity comes from the I/1/l naming convention, not from any attempt to hide an identifier. Nothing here is executable or obfuscated.

  52. info warn → info by review identifier-confusable-collision src/libImaging/Mode.h:7:5

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        IMAGING_MODE_1,
        IMAGING_MODE_CMYK,
        IMAGING_MODE_F,
    dismissed LLM, confidence 0.93 Enum declarations for Pillow image modes in a C header.
    Reasoning

    IMAGING_MODE_1 and a neighbouring mode constant are standard enum members of a well-known imaging library header. The skeleton match is a coincidence of short identifier names.

  53. info warn → info by review identifier-confusable-collision src/libImaging/Mode.h:43:5

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        // Non-rawmode aliases.
        IMAGING_RAWMODE_1,
        IMAGING_RAWMODE_CMYK,
        IMAGING_RAWMODE_F,
    dismissed LLM, confidence 0.93 Pillow header enum entries for rawmode aliases such as IMAGING_RAWMODE_1 and IMAGING_RAWMODE_CMYK.
    Reasoning

    The flagged names are documented as non-rawmode aliases in a header comment, with plain enum syntax. Nothing suggests concealment.

  54. info warn → info by review identifier-confusable-collision src/libImaging/Mode.h:67:5

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|_8` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        // Rawmodes
        IMAGING_RAWMODE_1_8,
        IMAGING_RAWMODE_1_I,
        IMAGING_RAWMODE_1_IR,
    dismissed LLM, confidence 0.93 Pillow header enum entries for 1-bit rawmode variants.
    Reasoning

    These are documented rawmode enum members with ordinary names. The identifier skeleton collision is a false positive from the confusability heuristic.

  55. info warn → info by review identifier-confusable-collision src/libImaging/Pack.c:542:6

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        /* bilevel */
        {IMAGING_MODE_1, IMAGING_RAWMODE_1, 1, pack1},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_I, 1, pack1I},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, pack1R},
    dismissed LLM, confidence 0.93 Pillow pack-function table rows for bilevel modes.
    Reasoning

    The table maps IMAGING_MODE_1 and IMAGING_RAWMODE_1_I to packing functions in a standard pack table. The shared visual skeleton is a naming coincidence in the source.

  56. info warn → info by review identifier-confusable-collision src/libImaging/Pack.c:542:22

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        /* bilevel */
        {IMAGING_MODE_1, IMAGING_RAWMODE_1, 1, pack1},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_I, 1, pack1I},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, pack1R},
    dismissed LLM, confidence 0.93 Pillow pack-function table entries for bilevel rawmodes.
    Reasoning

    The flagged identifiers are rawmode constants in a plain data table of pack functions, a standard structure in this library. The confusable match is a heuristic false positive.

  57. info warn → info by review identifier-confusable-collision src/libImaging/Storage.c:65:17

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    
        if (mode == IMAGING_MODE_1) {
            /* 1-bit images */
            im->bands = im->pixelsize = 1;
    dismissed LLM, confidence 0.93 Storage initialization branch for 1-bit images in Pillow.
    Reasoning

    This is an ordinary mode comparison, if (mode == IMAGING_MODE_1), setting band and pixel sizes for 1-bit images. It is standard, legitimate control flow.

  58. info warn → info by review identifier-confusable-collision src/libImaging/Unpack.c:249:1

    two identifiers collapse to visual skeleton `unpack|8` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

    static void
    unpack18(UINT8 *out, const UINT8 *in, int pixels) {
        /* Unpack a '|b1' image, which is a numpy boolean.
           1 == true, 0==false, in bytes */
    dismissed LLM, confidence 0.90 Pillow static unpack function for 1-bit numpy boolean images.
    Reasoning

    The flagged token is the function name unpack18 together with a comment mentioning a numpy boolean '|b1' format. The collision comes from the digit and letter pair in the name and comment, not from any hidden code.

  59. info warn → info by review identifier-confusable-collision src/libImaging/Unpack.c:1562:6

    two identifiers collapse to visual skeleton `|MAG|NG_MoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        /* bilevel */
        {IMAGING_MODE_1, IMAGING_RAWMODE_1, 1, unpack1},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_I, 1, unpack1I},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, unpack1R},
    dismissed LLM, confidence 0.93 Pillow unpack-function table rows for bilevel modes.
    Reasoning

    The unpack table rows pair IMAGING_MODE_1 with rawmode constants, a normal data table. The skeleton collision reflects naming conventions only.

  60. info warn → info by review identifier-confusable-collision src/libImaging/Unpack.c:1562:22

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        /* bilevel */
        {IMAGING_MODE_1, IMAGING_RAWMODE_1, 1, unpack1},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_I, 1, unpack1I},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, unpack1R},
    dismissed LLM, confidence 0.93 Pillow unpack-function table entries for bilevel rawmodes.
    Reasoning

    These rawmode identifiers index unpack functions in a standard table. The confusable-collision signal is a false positive from the heuristic.

  61. info warn → info by review identifier-confusable-collision src/libImaging/Unpack.c:1566:22

    two identifiers collapse to visual skeleton `|MAG|NG_RAWMoDE_|_8` (0/O/o and 1/l/I are confusable) (token pass, confidence 0.80)

        {IMAGING_MODE_1, IMAGING_RAWMODE_1_IR, 1, unpack1IR},
        {IMAGING_MODE_1, IMAGING_RAWMODE_1_8, 8, unpack18},
        {IMAGING_MODE_1, IMAGING_RAWMODE_L, 8, unpack18},
    dismissed LLM, confidence 0.93 Pillow unpack-function table entries for 1-bit and 8-bit rawmode variants.
    Reasoning

    The entries map 1-bit and 8-bit rawmode identifiers to unpack functions in an ordinary table. Nothing indicates obfuscation or malicious behaviour.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.1.0
git clone https://github.com/python-pillow/Pillow Pillow && cd Pillow
git checkout 13.0.0
disclude scan --severity info --diff 12.3.0 .