Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

cv2 import appends a trailing ":" to LD_LIBRARY_PATH — empty entry resolves to CWD and breaks child processes

Open
#1,268 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
70/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
linux, python

Research direction

Run the minimal reproduction, then inspect the POSIX branch of cv2/init.py around lines 146-147 and trace how BINARIES_PATHS is used. Done means importing cv2 no longer creates an empty LD_LIBRARY_PATH entry or causes unrelated child processes to inherit an unsafe path; add regression coverage if the repository provides a suitable test location.

Written by the indexing model from the issue text.

Description

Environment
  • opencv-python: reproduced on 4.11.0.86, 4.12.0.88, 4.13.0.92, 4.14.0.94 and 5.0.0.93 (PyPI manylinux x86_64 wheels; earliest tested 4.11.0.86, Jan 2025)
  • Python 3.13.15 / 3.14.7, Linux x86_64 (glibc; CachyOS/Arch, kernel 6.x)
Minimal reproduction
python -m venv venv && venv/bin/pip install opencv-python==5.0.0.93
venv/bin/python - <<'EOF'
import os, subprocess

print("before import:", repr(os.environ.get("LD_LIBRARY_PATH")))
import cv2
print("cv2", cv2.__version__, "after import:", repr(os.environ.get("LD_LIBRARY_PATH")))
print("child sees:", subprocess.run(["sh", "-c", "printf '%s' \"$LD_LIBRARY_PATH\""],
      capture_output=True, text=True).stdout)
EOF
Observed
before import: None
cv2 5.0.0 after import: '/…/site-packages/cv2/../../lib64:'
child sees: '/…/site-packages/cv2/../../lib64:'

cv2/__init__.py (POSIX branch, cv2/__init__.py:146-147 in current wheels):

# amending of LD_LIBRARY_PATH works for sub-processes only
os.environ['LD_LIBRARY_PATH'] = ':'.join(l_vars['BINARIES_PATHS']) + ':' + os.environ.get('LD_LIBRARY_PATH', '')

Three problems in one line:

  1. Unconditional trailing : — when LD_LIBRARY_PATH was previously unset the
    variable is created with a dangling separator. Per ld.so(8) semantics an empty
    entry resolves to the current working directory of every child process.
  2. Global environment mutation — the comment itself notes this "works for
    sub-processes only", yet the write persists in os.environ for the whole
    process lifetime, so every subprocess/os.system/webbrowser call made by
    the host application inherits the modified path. This is invisible side-channel
    state an importer cannot reasonably expect from import cv2.
  3. The injected directory typically does not exist — with standard manylinux
    wheel layouts the bundled libraries live in opencv_python.libs/ (located via
    $ORIGIN RPATH), and <site-packages>/cv2/../../lib64 is absent in venv,
    project, and standalone-packaged layouts, so the write buys nothing while
    adding the hazard.
Real-world impact

We ship a Nuitka-standalone application whose launcher cds into the release
folder. With cv2 imported, LD_LIBRARY_PATH ends with : → the release folder
(the CWD) enters the child loader path → children that load system OpenSSL
(xdg-open → kde-open, i.e. "open a URL in the default browser") resolve the
bundled, older libssl.so.3/libcrypto.so.3 instead of the system ones and die
with:

kde-open: libssl.so.3: version `OPENSSL_3.2.0' not found (required by /usr/lib/libcurl.so.4)

Any application that imports cv2 and then spawns helper processes from a
directory containing same-named libraries is affected the same way.

Suggested fix
  • Do not append a dangling separator; only write the variable when there is
    something to add and prepend/append with proper joining:

    paths = l_vars['BINARIES_PATHS']
    if paths:
        old = os.environ.get('LD_LIBRARY_PATH')
        os.environ['LD_LIBRARY_PATH'] = ':'.join(paths) + (':' + old if old else '')
    
  • Longer term, prefer not mutating the global environment at all: the bundled
    libraries are already found through $ORIGIN RPATH; if an env-based fallback
    is really needed, consider documenting it and cleaning up after import, or
    exposing an opt-in.

Happy to send a PR to opencv-python/opencv-python (the loader __init__.py)
if you agree with the direction.

Dominant language
Python
Stars
5.4k
Forks
1k
Avg merge
22h 17m
Merged PRs (30d)
3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from opencv/opencv-python

All issues in opencv/opencv-python

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.