PyPI / lxml / 6.1.3

lxml 6.1.3

Source
https://github.com/lxml/lxml
Tag scanned
lxml-6.1.3
Compared with
lxml-6.1.2-1 (0 signals introduced since)
Files
151 scanned, 199 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 1 warn · 18 info
Scan time
17.1 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 18 of 18 warn and critical signals; 17 demoted to info.
Disclude version
4.1.0
Scanned (UTC)
2026-10-22 00:43

Signals

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

  1. warn dynamic-execution benchmark/benchbase.py:209:9

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

            # create function object
            exec("\n".join(output), namespace)
            return namespace["element_factory"]
    likely benign LLM, confidence 0.50 exec used to build an element factory function in a benchmark helper.
    Reasoning

    exec of joined output to build a factory namespace; looks like generated code in a benchmark harness, a common legitimate pattern, though the source of output is not shown.

  2. info critical → info by review dynamic-execution doc/mkhtml.py:169:5

    `subprocess.call` with `shell=True` and a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

                    stylesheet_url, source_path, dest_path))
        subprocess.call(command, shell=True)
    likely benign LLM, confidence 0.75 Documentation build script that runs an HTML generation command through the shell.
    Reasoning

    The shell=True call runs a command assembled from stylesheet and file paths in a documentation build script. This is ordinary build tooling, not obfuscation, though the non-literal shell string is a minor hygiene concern.

  3. info critical → info by review dynamic-execution doc/mklatex.py:86:5

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

                    source_path, dest_path))
        os.system(command)
    
    def build_pygments_macros(filename):
    likely benign LLM, confidence 0.75 Documentation build helper that shells out to generate LaTeX output.
    Reasoning

    os.system runs a command built from source and destination paths in a documentation build helper. Nothing in the snippet suggests hidden or remote-supplied commands.

  4. info warn → info by review dynamic-execution doc/s5/ui/default/slides.js:552:30

    `setTimeout` called with a string argument — string form evaluates as code (ast pass, confidence 0.75)

    window.onload = startup;
    window.onresize = function(){setTimeout('fontScale()', 50);}
    likely benign LLM, confidence 0.85 Bundled S5 slideshow script that schedules a local font-scaling function by string name.
    Reasoning

    setTimeout with a string argument is an old idiom in the bundled S5 slideshow library. It calls a fixed local function name and has no encoded or remote payload.

  5. info critical → info by review dynamic-execution setupinfo.py:363:9

    `subprocess.Popen` with `shell=True` and a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

    
        p = subprocess.Popen(cmd, shell=True,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout_data, errors = p.communicate()
    likely benign LLM, confidence 0.70 Packaging setup helper that runs a shell command and captures its output.
    Reasoning

    Popen with shell=True runs a command string built at runtime in the packaging setup script. The command contents are not shown, so the risk cannot be fully ruled out, but this is typical of version or config probing during setup.

  6. info warn → info by review frame-introspection src/lxml/doctestcompare.py:461:13

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

        import sys
        frame = sys._getframe(1)
        while frame:
            l = frame.f_locals
    likely benign LLM, confidence 0.85 Doctest comparison helper that inspects caller frames to resolve local variables.
    Reasoning

    sys._getframe walks the caller stack to read locals, which is a standard technique in doctest comparison helpers that look up namespace values. It is legitimate library behavior.

  7. info warn → info by review dynamic-execution src/lxml/html/tests/test_html5parser.py:294:14

    `open(__file__)` — file reads its own source, common pattern for extracting payloads hidden in comments (ast pass, confidence 0.85)

            parser = DummyParser(doc='the doc')
            with open(__file__) as fp:
                self.assertEqual(self.call_it(fp, parser=parser), 'the doc')
                self.assertEqual(parser.parse_args, (fp,))
    likely benign LLM, confidence 0.85 Parser test that passes its own source file as input to a dummy parser.
    Reasoning

    The test opens its own source file as a file-like input to the parser under test. This is a common testing pattern and no payload extraction logic is visible.

  8. info warn → info by review dynamic-execution src/lxml/html/tests/transform_feedparser_data.py:51:20

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

                # Icky, but I'll trust it
                data = eval(match.group(1).strip())
                break
        c = None
    likely benign LLM, confidence 0.70 Test-data transform script that evaluates a Python literal captured from a fixture file.
    Reasoning

    eval runs on a regex-captured expression while converting feedparser test data. The author comments on the risk, and the input is developer-controlled test fixture data, so this is a poor practice rather than an attack.

  9. info warn → info by review frame-introspection src/lxml/tests/test_errors.py:37:13

    `sys.settrace` — call-stack frame introspection (ast pass, confidence 0.70)

            try:
                sys.settrace(None)
                gc.collect()
    likely benign LLM, confidence 0.90 Test cleanup that clears the global trace hook before garbage collection.
    Reasoning

    sys.settrace(None) clears the trace function, a standard cleanup step in tests that check for reference leaks or tracing interference.

  10. info warn → info by review frame-introspection src/lxml/tests/test_errors.py:55:13

    `sys.settrace` — call-stack frame introspection (ast pass, confidence 0.70)

            finally:
                sys.settrace(trace_func)
    
        def test_xmlsyntaxerror_has_info(self):
    likely benign LLM, confidence 0.90 Test teardown that restores the saved trace function.
    Reasoning

    Restoring the previous trace function in a finally block is routine test hygiene. It has no malicious function.

  11. info warn → info by review decoder-decompress-payload src/lxml/tests/test_etree.py:5058:20

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

            if compression:
                data = zlib.decompress(data)
            return canonicalize(data)
    likely benign LLM, confidence 0.90 Test helper that optionally decompresses XML test data before canonicalizing it.
    Reasoning

    zlib.decompress here handles data that the test itself compressed or received as test input, as part of a canonicalization helper. It is not a hidden payload.

  12. info warn → info by review dynamic-execution src/lxml/tests/test_incremental_xmlfile.py:713:9

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

            lns = {}
            exec(code, globals(), lns)
            test_async_xmlfile = lns['test_async_xmlfile']
    likely benign LLM, confidence 0.75 Test helper that execs generated code to define an async test function.
    Reasoning

    exec runs a code string that the test builds itself, then reads a test function from the namespace. This is a known pattern for generating async test variants, and the code source is local.

  13. info critical → info by review dynamic-import test.py:201:11

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

            cov.start()
        mod = __import__(modname)
        if cov is not None:
            cov.stop()
    likely benign LLM, confidence 0.90 Test runner function that dynamically imports a named test module.
    Reasoning

    __import__ with a module name in a test runner loads a test module by name during coverage-wrapped execution. This is standard dynamic import for test discovery.

  14. info dynamic-execution tools/ci-run.sh:61:3

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

      which ${CC%% *}
      ${CC%% *} --version
    fi
    if [ -z "${OS_NAME##win*}" ]; then
  15. info warn → info by review dynamic-execution tools/manylinux/build-wheels.sh:33:9

    command name is a variable (`$PYBIN`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

        for PYBIN in /opt/python/${PYTHON_BUILD_VERSION}/bin/; do
            ${PYBIN}/python -m pip install $PACKAGE --no-index -f /io/$WHEELHOUSE | tee install.txt || exit 1
    
            # check import as a quick test
    likely benign LLM, confidence 0.90 Wheel build loop that runs pip from each installed Python interpreter directory.
    Reasoning

    The loop variable PYBIN iterates over a fixed /opt/python glob in a manylinux wheel build script. The variable is set by the loop, so the 'unset in this file' flag is a false positive.

  16. info warn → info by review dynamic-execution tools/manylinux/build-wheels.sh:36:20

    command name is a variable (`$PYBIN`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

            # check import as a quick test
            (cd $HOME; ${PYBIN}/python -c 'import lxml.etree, lxml.objectify') || {
              # Allow PyPy to fail the import due to C-API differences for 'str' (PyVarObject or not).
              echo "${PYBIN}" | fgrep -q pypy || exit 1
    likely benign LLM, confidence 0.90 Wheel build step that runs a basic lxml import check under each Python interpreter.
    Reasoning

    PYBIN is the same loop variable from the enclosing for loop, used to run a quick import check. This is routine CI build logic.

  17. info warn → info by review dynamic-execution tools/manylinux/build-wheels.sh:51:5

    command name is a variable (`$CC`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

        echo "Python versions found: $(cd /opt/python && echo cp* | sed -e 's|[^ ]*-||g')"
        ${CC:-gcc} --version
    }
    likely benign LLM, confidence 0.90 A build helper probes the configured C compiler version using the CC variable with a gcc fallback.
    Reasoning

    The flagged line runs ${CC:-gcc} --version, a standard build-toolchain probe in a manylinux wheel build script. CC is a conventional compiler override, and the default is gcc. The dynamic command name is normal for build scripts and does not show obfuscation or malicious intent.

  18. info warn → info by review dynamic-execution tools/manylinux/build-wheels.sh:63:16

    command name is a variable (`$PYBIN`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

            test -n "$source" -o ! -e "$REQUIREMENTS" \
                || ${PYBIN}/python -m pip install -r "$REQUIREMENTS"
    
            echo "Starting build with $($PYBIN/python -V)"
    likely benign LLM, confidence 0.88 The script runs pip install from a selected Python interpreter's bin directory during wheel building.
    Reasoning

    ${PYBIN}/python -m pip install -r is a routine build step that installs requirements into a selected Python interpreter. PYBIN is a path set by the build driver, and the script is a manylinux wheel builder where this is expected. No encoding or hidden execution is present.

  19. info warn → info by review dynamic-execution tools/manylinux/build-wheels.sh:65:37

    command name is a variable (`$PYBIN`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

    
            echo "Starting build with $($PYBIN/python -V)"
            build_wheel "$PYBIN" "$source" &
            THIRD=$!
    likely benign LLM, confidence 0.88 The build script reports the active Python interpreter version and starts a wheel build using it.
    Reasoning

    The snippet prints the interpreter version and then launches build_wheel with PYBIN as an argument. This is ordinary build orchestration for selecting a Python version per wheel. The variable-based command is the expected pattern for a multi-interpreter build script.

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/lxml/lxml lxml && cd lxml
git checkout lxml-6.1.3
disclude scan --severity info --diff lxml-6.1.2-1 .