CVE-2024-40647: Insufficient Information (NVD-CWE-noinfo)
value: sentry-sdk is the official Python SDK for Sentry.io. A bug in Sentry's Python SDK < 2.8.0 allows the environment variables to be passed to subprocesses despite the `env={}` setting. In Python's `subprocess` calls, all environment variables are passed to subprocesses by default. However, if you specifically do not want them to be passed to subprocesses, you may use `env` argument in `subprocess` calls. Due to the bug in Sentry SDK, with the Stdlib integration enabled (which is enabled by default), this expectation is not fulfilled, and all environment variables are being passed to subprocesses instead. The issue has been patched in pull request #3251 and is included in sentry-sdk==2.8.0. We strongly recommend upgrading to the latest SDK version. However, if it's not possible, and if passing environment variables to child processes poses a security risk for you, you can disable all default integrations.

CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-07-18T17:15Z
Repository: https://github.com/getsentry/sentry-python
Language: Python
Files changed: sentry_sdk/integrations/stdlib.py, tests/integrations/stdlib/test_subprocess.py
Commit date: 2024-07-08 09:38:14 +0200
Commit message: fix(integrations): don't send full env to subprocess (#3251)

During the arguments modification to `subprocess.Popen.__init__`,
an explicitly empty environment of `{}` is incorrectly confused with a `None`
environment. This causes sentry to pass the entire environment of the
parent process instead of sending just the injected environment variables.

Fix it by only replacing the environment with `os.environ` if the variable
is None, and not just falsy.

---------

Co-authored-by: Kevin Michel <kevin.michel@aiven.io>
Diff: diff --git a/sentry_sdk/integrations/stdlib.py b/sentry_sdk/integrations/stdlib.py
index 58e561d4..e0b4d067 100644
--- a/sentry_sdk/integrations/stdlib.py
+++ b/sentry_sdk/integrations/stdlib.py
@@ -205,11 +205,15 @@ def _install_subprocess():
             for k, v in Scope.get_current_scope().iter_trace_propagation_headers(
                 span=span
             ):
                 if env is None:
                     env = _init_argument(
-                        a, kw, "env", 10, lambda x: dict(x or os.environ)
+                        a,
+                        kw,
+                        "env",
+                        10,
+                        lambda x: dict(x if x is not None else os.environ),
                     )
                 env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
 
             if cwd:
                 span.set_data("subprocess.cwd", cwd)
diff --git a/tests/integrations/stdlib/test_subprocess.py b/tests/integrations/stdlib/test_subprocess.py
index 1e0d6314..593ef8a0 100644
--- a/tests/integrations/stdlib/test_subprocess.py
+++ b/tests/integrations/stdlib/test_subprocess.py
@@ -172,10 +172,23 @@ def test_subprocess_basic(
         assert subprocess_init_span["description"].startswith("<")
     else:
         assert sys.executable + " -c" in subprocess_init_span["description"]
 
 
+def test_subprocess_empty_env(sentry_init, monkeypatch):
+    monkeypatch.setenv("TEST_MARKER", "should_not_be_seen")
+    sentry_init(integrations=[StdlibIntegration()], traces_sample_rate=1.0)
+    with start_transaction(name="foo"):
+        args = [
+            sys.executable,
+            "-c",
+            "import os; print(os.environ.get('TEST_MARKER', None))",
+        ]
+        output = subprocess.check_output(args, env={}, universal_newlines=True)
+    assert "should_not_be_seen" not in output
+
+
 def test_subprocess_invalid_args(sentry_init):
     sentry_init(integrations=[StdlibIntegration()])
 
     with pytest.raises(TypeError) as excinfo:
         subprocess.Popen(1)

Vulnerable code:                         a, kw, "env", 10, lambda x: dict(x or os.environ)
Fixed code:                         a,
                        kw,
                        "env",
                        10,
                        lambda x: dict(x if x is not None else os.environ),
def test_subprocess_empty_env(sentry_init, monkeypatch):
    monkeypatch.setenv("TEST_MARKER", "should_not_be_seen")
    sentry_init(integrations=[StdlibIntegration()], traces_sample_rate=1.0)
    with start_transaction(name="foo"):
        args = [
            sys.executable,
            "-c",
            "import os; print(os.environ.get('TEST_MARKER', None))",
        ]
        output = subprocess.check_output(args, env={}, universal_newlines=True)
    assert "should_not_be_seen" not in output