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
150 scanned, 200 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 19 info
Scan time
13.1 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 18 of 18 warn and critical signals; 18 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:23

Signals

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

  1. info warn → info by review 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.80 exec used to build a generated element_factory function in a benchmark script.
    Reasoning

    exec of a joined list of generated lines to build a factory function namespace; this is a known pattern in benchmark code generation, with no obfuscation or network activity visible.

  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 Doc build script invokes a shell command built from local paths.
    Reasoning

    Documentation build script runs a locally constructed command with shell=True for stylesheet and path processing. Shell use is poor practice but the context is a doc build, not a dropper.

  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 Doc build script calls os.system on a locally built LaTeX/pygments command.
    Reasoning

    Doc build helper calls os.system on a command assembled from local source and destination paths. Benign build tooling, though it is an unsafe shell pattern.

  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.80 setTimeout with a constant string calling fontScale in an S5 slideshow script.
    Reasoning

    Legacy S5 slideshow code passes a constant string to setTimeout to call fontScale; the string is a fixed literal, not attacker-controlled.

  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 setup-time helper runs a shell command via Popen with shell=True.
    Reasoning

    Setup helper runs a shell command via Popen to query build information, likely version or tool output from the local environment. The command is not shown as attacker-supplied.

  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 Frame walking in doctest comparison to read caller locals.
    Reasoning

    sys._getframe used to walk frames to fetch caller locals, a standard technique in doctest comparison helpers for namespace lookup. Not malicious.

  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 Test reads its own file as input to a dummy parser.
    Reasoning

    Test opens its own source file to pass a file object to a parser under test. This is a normal test fixture, not payload extraction.

  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.80 eval of a captured expression in a feedparser test data transform.
    Reasoning

    eval applied to a regex capture from test data in a feedparser transform test. It is data-driven test scaffolding; the comment acknowledges it. Some risk if the input is untrusted, but this is test code.

  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 clears the trace function before garbage collection.
    Reasoning

    sys.settrace(None) is used in a test to clear tracing before gc, a routine test-harness action.

  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 restores the trace function in a finally block.
    Reasoning

    Restoring a previously saved trace function in a finally block is standard test cleanup.

  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.85 Optional zlib decompression of test XML data before canonicalization.
    Reasoning

    zlib decompression of test data inside a canonicalization helper, guarded by a compression flag. Ordinary test/library behavior with no 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.85 exec used to define an async test function in a test module.
    Reasoning

    exec of a code string defining an async test function into a local namespace. Test-generation pattern with no external or hidden input visible.

  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.85 Test runner dynamically imports a named test module.
    Reasoning

    __import__ of a module name in a test runner, driven by the test harness's module argument. Common for dynamic test discovery; the critical severity overstates it given the context.

  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 Loop runs pip install using the Python interpreter from each /opt/python bin directory.
    Reasoning

    PYBIN is the loop variable over /opt/python/${PYTHON_BUILD_VERSION}/bin/, which is a fixed toolchain location. Running ${PYBIN}/python to install the package is the ordinary way a manylinux build script drives multiple Python interpreters. The variable-command flag is a generic AST heuristic, and nothing here is obfuscated or hidden.

  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 Import smoke test for lxml under each Python interpreter, with a PyPy exception.
    Reasoning

    This runs a quick import check with the same loop-derived interpreter path, in a subshell from $HOME. The PyPy-tolerant fallback is a documented compatibility accommodation for C-API differences. No network fetch, encoding, or hidden payload is present.

  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 Prints the C compiler version, defaulting to gcc when CC is unset.
    Reasoning

    ${CC:-gcc} is a standard way to honor a CC override while defaulting to gcc, used only to print the compiler version. The flagged command is a conventional build-environment check.

  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.90 Installs requirements and logs the Python version using the loop-selected interpreter.
    Reasoning

    PYBIN comes from the same controlled loop over /opt/python interpreters. It is used to install requirements and to print the Python version for logging. This is routine build-script behavior.

  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.90 Starts a background wheel build with the selected interpreter and logs its version.
    Reasoning

    The command runs build_wheel with PYBIN as an argument, and the version echo uses the same interpreter. Both act on the trusted toolchain paths defined earlier. No suspicious constructs are visible in the snippet.

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