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
40.4 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 56 of 56 warn and critical signals; 56 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-17 14:41

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.90 Base64-encoded test image data embedded in a libtiff test file.
    Reasoning

    The base64-like blob is a short literal of raw pixel test data inside a unit test for libtiff. It is a fixture, not a hidden payload, and the raw pass has a high false-positive rate for this kind of content.

  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.90 Coordinate parameters in a line-drawing function flagged by the confusability heuristic.
    Reasoning

    y1 and similar short coordinate names are ordinary in a drawing routine; the collision is a heuristic artifact.

  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"},
    likely benign LLM, confidence 0.95 Pillow L-mode raw-mode mapping table whose names collide visually.
    Reasoning

    The entries are a mapping table of Pillow L-mode raw modes (L;1, L;2, L;2I, L;16B). The collision is between legitimately distinct names that differ by I versus 1 or by a digit. This is a naming artifact, not obfuscation.

  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,
    likely benign LLM, confidence 0.95 Pillow L-mode rawmode enum constants with confusable-looking names.
    Reasoning

    The snippet lists Pillow L-mode rawmode enum constants (IMAGING_RAWMODE_L_1, L_16, L_16B). The skeleton match comes from legitimate distinct names, a common false positive for this rule.

  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.92 Concatenated bytes literal encoding a synthetic TIFF file for a metadata test.
    Reasoning

    The bytes literal is a hand-built TIFF header and IFD used as an in-memory BytesIO fixture for metadata parsing tests. The escapes are binary test data, which is expected in this context.

  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.85 Pickled PIL PngImageFile bytes used as a fixture in a pickle round-trip test.
    Reasoning

    The bytes are a pickle stream of a PIL PngImageFile, passed to pickle.loads in a test of pickling image objects. Loading a fixed, trusted test fixture is normal here, though pickle loading is a known risk pattern in general.

  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 Build-script lookup of a library root through globals() combined with environment variables.
    Reasoning

    The code looks up a root module by name in globals() and then checks os.environ, which matches the build script's logic for locating optional library roots from environment variables. It is a build-configuration lookup with a fixed set of names.

  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.90 Module-level constants are populated from a static COMPRESSIONS table via vars().
    Reasoning

    The loop writes compression constants from the COMPRESSIONS dict into module globals via vars(), which is a common way to define named constants from a table. The keys are fixed, so nothing is dynamically or maliciously determined.

  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.92 Base64-encoded PNG sample embedded in a docstring.
    Reasoning

    The base64 blob is a PNG image embedded in a docstring example for ImageFont. The raw-pass encoding signal is expected for an embedded sample image and has no execution path.

  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 Restricted eval-mode compilation of ImageMath expressions, followed by a code-safety scan.
    Reasoning

    ImageMath deliberately compiles user expressions in eval mode and runs a scan() over the compiled code to restrict allowed names and operations. This is a restricted expression evaluator, which is legitimate, though compile on a non-literal is still a sensitive pattern.

  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 Image viewer launch through os.system using a command built from the image path.
    Reasoning

    os.system runs the external image viewer command built by get_command for the file being shown. This is the expected viewer-launch mechanism, with a nosec marker. The command is not attacker-controlled in normal use, but the non-literal shell call warrants a look at how path is sanitized.

  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.90 FlateDecode stream decompression in the PDF parser.
    Reasoning

    zlib.decompressobj is used to decode FlateDecode streams inside a PDF parser, with max_length bounding the output. This is the standard PDF filter handling for legitimate documents.

  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.95 Octal escapes defining PDF delimiter and whitespace character classes in a regex.
    Reasoning

    The escapes are octal character codes inside regex character classes for PDF whitespace and delimiter sets. This is ordinary regex syntax, not obfuscation.

  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.95 Octal escapes in a PDF delimiter regex character class.
    Reasoning

    The escapes are octal character codes in a regex character class for PDF delimiter and whitespace sets, matching the PDF spec. This is ordinary regex syntax.

  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.95 Octal escapes in a PDF whitespace regex character class.
    Reasoning

    The escapes are octal character codes in a regex character class for PDF whitespace. This is ordinary regex syntax from the PDF spec.

  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.93 Size-bounded zlib decompression of PNG text chunk data.
    Reasoning

    The helper decompresses PNG text chunks with zlib.decompressobj and caps the output at MAX_TEXT_CHUNK. The size limit is a defensive measure against decompression bombs, so this is safe 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 256-color palette embedded as a bytes literal in the WAL image reader.
    Reasoning

    The byte literal is the default Quake WAL palette, a 768-byte color table with a cited source (piffo). Binary constant data in an image library is expected.

  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 default palette byte table.
    Reasoning

    Raw hex escapes in this file are the palette data continuing; it is a legitimate constant table and the entropy is typical of palette values, not an encoded payload.

  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 default WAL palette constant.
    Reasoning

    Same palette table; the values are smooth, monotonic color ramps, consistent with a real palette rather than hidden code.

  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 Palette data rows within the WAL default palette.
    Reasoning

    Palette data rows within the same legitimate constant table.

  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 data continuation in WalImageFile.py.
    Reasoning

    Palette data continuation; no execution or decoding of this data occurs in the snippet.

  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 in the WAL default color table.
    Reasoning

    Palette rows with a regular descending pattern, consistent with a color table.

  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 Tail of the default WAL palette bytes literal.
    Reasoning

    End of the palette constant; closing paren of a bytes literal with no decoding or execution.

  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 Final palette row of the WAL default color table.
    Reasoning

    Final palette row; legitimate constant data.

  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:
    likely benign LLM, confidence 0.85 Feature-detection helper importing optional PIL dependency modules by name.
    Reasoning

    Pillow's check_module uses __import__ on a module name parameter to test whether optional dependencies are installed. The module names come from internal code, not untrusted input, so this is a standard feature-detection pattern.

  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)
    likely benign LLM, confidence 0.85 Imports an optional dependency to read its version string.
    Reasoning

    Version lookup helper imports a known optional library by name and reads its version attribute; the names are internal constants, consistent with Pillow's features module.

  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:
    likely benign LLM, confidence 0.85 Imports an optional module to check for a feature flag attribute.
    Reasoning

    Dynamic import of a module name passed internally to check a feature flag attribute, matching Pillow's normal optional-dependency probing.

  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)
    likely benign LLM, confidence 0.85 Imports an optional dependency to read its version.
    Reasoning

    Same version-lookup helper pattern as earlier in the file, importing known optional packages by internal name.

  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.80 Runtime resolution of Tk library function pointers via dlsym.
    Reasoning

    tkImaging loads Tk stub functions by name via dlsym from a library handle, a known pattern for resolving Tk symbols at runtime. The names are internal constants, not attacker-controlled, though the non-literal argument is what triggers the signal.

  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.80 dlopen of the main program handle to locate Tk symbols.
    Reasoning

    Loads from the main program namespace via dlopen(NULL) and closes the handle, a standard way to find already-linked Tk symbols; no attacker-controlled path is visible.

  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 module library located at runtime, as Pillow does for Tk image support.
    Reasoning

    Pillow's tkImaging.c dlopens the tkinter shared library whose path is computed from the Tk/Python installation at runtime. This is a standard, legitimate pattern for locating a module file; the snippet shows an error message consistent with that purpose.

  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.90 Pillow mode-constant identifiers flagged for visual similarity in a normal accessor table.
    Reasoning

    IMAGING_MODE_1 and IMAGING_MODE_L collapse to a skeleton with IMAGING_MODE_ names because of the uppercase letter set (I, L, O). These are ordinary macro names from Pillow's image mode constants, and the collision comes from the identifier-skeleton heuristic, not from any actual confusable substitution.

  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.90 Standard image-mode constant comparisons in a conversion routine.
    Reasoning

    Comparisons against IMAGING_MODE_1 and IMAGING_MODE_L are ordinary uppercase mode constants; the skeleton collision is a false positive from the heuristic treating I/L/O as confusable.

  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.90 Short coordinate variables in a line-drawing routine flagged for visual similarity.
    Reasoning

    xo and yo are ordinary coordinate variable names (x0/xo, y0/yo style in line-drawing code). Short names like these collide under the skeleton heuristic and carry no obfuscation intent.

  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.90 Coordinate variable names in a drawing routine flagged by the confusability heuristic.
    Reasoning

    Same as the previous finding: ymin/ymax-style coordinate names trigger the confusable heuristic on common short identifiers in standard graphics code.

  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.90 Coordinate parameters in a horizontal line drawing helper.
    Reasoning

    x0 and y0 are common coordinate parameter names; the skeleton collision reflects the digit-zero/letter-O ambiguity in short names, a false positive.

  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.90 Short scanline state arrays in a polygon/fill routine flagged for similarity.
    Reasoning

    cy, cl, cr are arrays of scanline state; the collision with another short name is incidental to the heuristic and reflects no obfuscation.

  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.90 Angle parameters in a normalization helper flagged by the confusable heuristic.
    Reasoning

    al and ar are angle parameters in a standard normalize function; the skeleton collision is a false positive on short names.

  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.90 Image mode validation in a fill routine flagged for identifier similarity.
    Reasoning

    Mode comparisons against IMAGING_MODE_* constants are ordinary validation code; the skeleton collision is from uppercase letters.

  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.90 Coordinate parameters in a geometry function flagged for similarity.
    Reasoning

    x0/x1-style coordinate parameters in a geometry transform are standard; the collision is a heuristic false positive.

  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.90 Coordinate parameters in a geometry function flagged for similarity.
    Reasoning

    y0/y1 coordinate parameters in a geometry function are ordinary; the skeleton collision is spurious.

  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 Portability macro mapping FLOAT32 to the float type in Pillow's platform header.
    Reasoning

    Pillow's ImPlatform.h defines FLOAT32 as float for portable typedef-style aliasing of fixed-width float types across platforms. This is a well-known legitimate portability idiom, not an attempt to hide malicious code.

  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 Portability macro mapping FLOAT64 to the double type in Pillow's platform header.
    Reasoning

    Same portability idiom as FLOAT32: FLOAT64 mapped to double in Pillow's platform header for consistent type naming.

  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.90 Image mode name lookup table flagged for identifier similarity.
    Reasoning

    Mode name table entries for IMAGING_MODE_* constants; the skeleton collision is caused by uppercase letters in ordinary identifiers.

  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.90 Raw mode name lookup table flagged for identifier similarity.
    Reasoning

    RAWMODE name table entries are standard designated-initializer data; the collision is a heuristic false positive.

  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"},
    likely benign LLM, confidence 0.95 Table of Pillow raw-mode identifier-to-string mappings with names that differ only in confusable characters like 1 and I.
    Reasoning

    This is a static table of Pillow raw-mode names such as IMAGING_RAWMODE_1_8 and IMAGING_RAWMODE_1_I. The skeleton collision comes from the legitimate names 1 and I, which are distinct mode identifiers for different bit depths. Token-pass confusable heuristics fire on such names routinely, and nothing here is executable or encoded.

  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,
    likely benign LLM, confidence 0.95 Pillow image-mode enum declaration with visually similar identifiers.
    Reasoning

    This is a C enum of Pillow image modes (IMAGING_MODE_1, IMAGING_MODE_CMYK, IMAGING_MODE_F). The skeleton collision reflects the distinct, meaningful names IMAGING_MODE_1 and IMAGING_MODE_I, which is normal for a header.

  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,
    likely benign LLM, confidence 0.95 Pillow rawmode alias enum with confusable-looking identifier names.
    Reasoning

    This is an enum block of Pillow rawmode aliases. The flagged names are distinct legitimate identifiers whose letters and digits look alike, so the confusable heuristic fires on ordinary code.

  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,
    likely benign LLM, confidence 0.95 Pillow rawmode enum constants whose names collide under confusable folding.
    Reasoning

    The snippet lists Pillow rawmode enum constants (IMAGING_RAWMODE_1_8, _1_I, _1_IR). Their differences are legitimate suffixes; the collision is a heuristic artifact of the digit 1 and letter I.

  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},
    likely benign LLM, confidence 0.95 Pillow pack-function dispatch table for bilevel modes.
    Reasoning

    This is a Pillow pack-table row using IMAGING_MODE_1 and IMAGING_RAWMODE_1_I with pack functions. The collision reflects distinct legitimate identifiers. The code is ordinary image packing logic.

  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},
    likely benign LLM, confidence 0.95 Pillow bilevel pack-dispatch table entry with confusable-looking rawmode names.
    Reasoning

    Same table as the other Pack.c finding: a bilevel pack-dispatch table with legitimately named rawmode constants. The confusable warning is a false positive on distinct names.

  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;
    likely benign LLM, confidence 0.95 Pillow storage setup branch for 1-bit images.
    Reasoning

    The code checks mode == IMAGING_MODE_1 and sets bands and pixelsize for 1-bit images. That is standard Pillow storage initialization. The collision comes from the legitimate mode name.

  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 */
    likely benign LLM, confidence 0.95 Pillow byte-to-1-bit unpack function for numpy boolean images.
    Reasoning

    unpack18 is a Pillow unpacker for boolean (|b1) numpy images, with a comment explaining the byte semantics. The skeleton collision with unpack8 is a naming coincidence, and the function body is ordinary pixel unpacking.

  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},
    likely benign LLM, confidence 0.95 Pillow bilevel unpack-dispatch table.
    Reasoning

    This is a Pillow unpack-dispatch table for bilevel modes, with distinct legitimately named unpack functions and rawmode constants. The rule's confusable match is spurious here.

  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},
    likely benign LLM, confidence 0.95 Pillow bilevel unpack-dispatch table entry with confusable-looking rawmode names.
    Reasoning

    Same bilevel unpack table as the other Unpack.c finding, with legitimately named constants whose skeletons collide. Benign.

  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},
    likely benign LLM, confidence 0.95 Pillow unpack-dispatch table rows mapping 1-bit rawmodes to unpack functions.
    Reasoning

    The snippet is a continuation of the Pillow unpack-dispatch table, mapping rawmodes such as IMAGING_RAWMODE_1_8 to unpack18. The confusable collision is a naming artifact, and the code is ordinary image-decoding dispatch.

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.0.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 .