Skip to content

Security: backend pip-audit detected vulnerabilities #41

@github-actions

Description

@github-actions

Backend pip-audit flagged vulnerabilities

Report

{"dependencies": [{"name": "aicrm-backend", "skip_reason": "Dependency not found on PyPI and could not be audited: aicrm-backend (0.1.0)"}, {"name": "alembic", "version": "1.18.4", "vulns": []}, {"name": "annotated-doc", "version": "0.0.4", "vulns": []}, {"name": "annotated-types", "version": "0.7.0", "vulns": []}, {"name": "anyio", "version": "4.12.1", "vulns": []}, {"name": "argon2-cffi", "version": "25.1.0", "vulns": []}, {"name": "argon2-cffi-bindings", "version": "25.1.0", "vulns": []}, {"name": "asgiref", "version": "3.11.1", "vulns": []}, {"name": "ast-serialize", "version": "0.4.0", "vulns": []}, {"name": "asyncpg", "version": "0.31.0", "vulns": []}, {"name": "attrs", "version": "26.1.0", "vulns": []}, {"name": "bcrypt", "version": "5.0.0", "vulns": []}, {"name": "beautifulsoup4", "version": "4.14.3", "vulns": []}, {"name": "boolean-py", "version": "5.0", "vulns": []}, {"name": "cachecontrol", "version": "0.14.4", "vulns": []}, {"name": "certifi", "version": "2026.1.4", "vulns": []}, {"name": "cffi", "version": "2.0.0", "vulns": []}, {"name": "charset-normalizer", "version": "3.4.6", "vulns": []}, {"name": "click", "version": "8.3.1", "vulns": []}, {"name": "coverage", "version": "7.13.2", "vulns": []}, {"name": "cryptography", "version": "48.0.0", "vulns": []}, {"name": "cyclonedx-python-lib", "version": "11.7.0", "vulns": []}, {"name": "defusedxml", "version": "0.7.1", "vulns": []}, {"name": "deprecated", "version": "1.3.1", "vulns": []}, {"name": "distro", "version": "1.9.0", "vulns": []}, {"name": "dnspython", "version": "2.8.0", "vulns": []}, {"name": "email-validator", "version": "2.3.0", "vulns": []}, {"name": "factory-boy", "version": "3.3.3", "vulns": []}, {"name": "faker", "version": "40.18.0", "vulns": []}, {"name": "fastapi", "version": "0.136.1", "vulns": []}, {"name": "filelock", "version": "3.29.0", "vulns": []}, {"name": "googleapis-common-protos", "version": "1.75.0", "vulns": []}, {"name": "greenlet", "version": "3.3.1", "vulns": []}, {"name": "grpcio", "version": "1.80.0", "vulns": []}, {"name": "h11", "version": "0.16.0", "vulns": []}, {"name": "httpcore", "version": "1.0.9", "vulns": []}, {"name": "httptools", "version": "0.7.1", "vulns": []}, {"name": "httpx", "version": "0.28.1", "vulns": []}, {"name": "idna", "version": "3.11", "vulns": []}, {"name": "importlib-metadata", "version": "8.7.1", "vulns": []}, {"name": "iniconfig", "version": "2.3.0", "vulns": []}, {"name": "jiter", "version": "0.12.0", "vulns": []}, {"name": "joblib", "version": "1.5.3", "vulns": []}, {"name": "librt", "version": "0.11.0", "vulns": []}, {"name": "license-expression", "version": "30.4.4", "vulns": []}, {"name": "mako", "version": "1.3.10", "vulns": [{"id": "CVE-2026-44307", "fix_versions": ["1.3.12"], "aliases": ["GHSA-2h4p-vjrc-8xpq"], "description": "## Summary  On Windows, a URI using backslash traversal (e.g. `\\..\\..\\ secret.txt`) bypasses the directory traversal check in `Template.__init__` and the `posixpath`-based normalization in `TemplateLookup.get_template()`, allowing reads of files outside the configured template directory.   ## Details  The root cause is a mismatch between `posixpath` (used for URI normalization in `get_template()`) and `os.path` (used for file access via `os.path.isfile()` and validation via `os.path.normpath()` in `Template.__init__`). On Windows, `os.path` is `ntpath`, which treats `\\` as a path separator, while `posixpath` treats it as a literal character.  The vulnerability chain:  1. `get_template()` strips only leading `/` via `re.sub(r\"^\\/+\", \"\", uri)` and normalizes with `posixpath` \u2014 backslash `\\` is treated as a literal character, so `\\..\\ secret.txt` passes through with `..` undetected. 2. `Template.__init__()` validation uses `os.path.normpath()` \u2014 on Windows this resolves `\\..\\ secret.txt` to `\\secret.txt`, which does not start with `..`, so the `startswith(\"..\")` check passes. 3. `os.path.isfile()` on Windows interprets `\\` as a path separator, resolving the `..` traversal and finding files outside the template directory.  ### Affected code  - `mako/lookup.py`: `TemplateLookup.get_template()` uses `posixpath.normpath`/`posixpath.join` for path construction but `os.path.isfile()` for existence check - `mako/template.py`: `Template.__init__()` URI validation uses `os.path.normpath()` which on Windows resolves backslash traversal to a form that passes the `startswith(\"..\")` guard  ## Impact  If an application passes user-controlled template names or include paths to `TemplateLookup.get_template()`, an attacker on Windows may be able to load and disclose readable files outside the configured template directory. The primary impact is local file disclosure. If the targeted file contains Mako/Python template syntax, it may also be parsed and executed as a template.  ## Remediation  The fix should normalize backslashes to forward slashes early in the URI processing pipeline, before any path operations, to ensure consistent behavior across platforms."}]}, {"name": "markdown-it-py", "version": "4.2.0", "vulns": []}, {"name": "markupsafe", "version": "3.0.3", "vulns": []}, {"name": "mdurl", "version": "0.1.2", "vulns": []}, {"name": "msgpack", "version": "1.1.2", "vulns": []}, {"name": "mypy", "version": "2.1.0", "vulns": []}, {"name": "mypy-extensions", "version": "1.1.0", "vulns": []}, {"name": "numpy", "version": "2.4.2", "vulns": []}, {"name": "openai", "version": "2.36.0", "vulns": []}, {"name": "opentelemetry-api", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-distro", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-exporter-otlp", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-exporter-otlp-proto-grpc", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-instrumentation", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-instrumentation-asgi", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-instrumentation-fastapi", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-instrumentation-httpx", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-instrumentation-redis", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-instrumentation-sqlalchemy", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-proto", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-sdk", "version": "1.41.1", "vulns": []}, {"name": "opentelemetry-semantic-conventions", "version": "0.62b1", "vulns": []}, {"name": "opentelemetry-util-http", "version": "0.62b1", "vulns": []}, {"name": "packageurl-python", "version": "0.17.6", "vulns": []}, {"name": "packaging", "version": "26.0", "vulns": []}, {"name": "pathspec", "version": "1.0.4", "vulns": []}, {"name": "phonenumbers", "version": "9.0.22", "vulns": []}, {"name": "pip", "version": "26.1.1", "vulns": []}, {"name": "pip-api", "version": "0.0.34", "vulns": []}, {"name": "pip-audit", "version": "2.10.0", "vulns": []}, {"name": "pip-requirements-parser", "version": "32.0.1", "vulns": []}, {"name": "platformdirs", "version": "4.9.6", "vulns": []}, {"name": "pluggy", "version": "1.6.0", "vulns": []}, {"name": "prometheus-client", "version": "0.25.0", "vulns": []}, {"name": "prometheus-fastapi-instrumentator", "version": "7.1.0", "vulns": []}, {"name": "protobuf", "version": "6.33.6", "vulns": []}, {"name": "py-serializable", "version": "2.1.0", "vulns": []}, {"name": "pybreaker", "version": "1.4.1", "vulns": []}, {"name": "pycparser", "version": "3.0", "vulns": []}, {"name": "pydantic", "version": "2.13.4", "vulns": []}, {"name": "pydantic-core", "version": "2.46.4", "vulns": []}, {"name": "pydantic-settings", "version": "2.14.1", "vulns": []}, {"name": "pygments", "version": "2.19.2", "vulns": [{"id": "CVE-2026-4539", "fix_versions": ["2.20.0"], "aliases": ["GHSA-5239-wwwm-4pmq"], "description": "A security flaw has been discovered in pygments before 2.20.0. The impacted element is the function AdlLexer of the file pygments/lexers/archetype.py. The manipulation results in inefficient regular expression complexity. The attack is only possible with local access. The exploit has been released to the public and may be used for attacks. The project was informed of the problem early through an issue report but has not responded yet."}]}, {"name": "pyjwt", "version": "2.12.1", "vulns": []}, {"name": "pyparsing", "version": "3.3.2", "vulns": []}, {"name": "pytest", "version": "9.0.3", "vulns": []}, {"name": "pytest-asyncio", "version": "1.3.0", "vulns": []}, {"name": "pytest-cov", "version": "7.1.0", "vulns": []}, {"name": "python-dateutil", "version": "2.9.0.post0", "vulns": []}, {"name": "python-dotenv", "version": "1.2.1", "vulns": [{"id": "CVE-2026-28684", "fix_versions": ["1.2.2"], "aliases": ["GHSA-mf9w-mj56-hr94"], "description": "### Summary  `set_key()` and `unset_key()` in python-dotenv follow symbolic links when rewriting `.env` files, allowing a local attacker to overwrite arbitrary files via a crafted symlink when a cross-device rename fallback is triggered.   ### Details  The `rewrite()` context manager in `dotenv/main.py` is used by both `set_key()` and `unset_key()` to safely modify `.env` files. It works by writing to a temporary file (created in the system's default temp directory, typically `/tmp`) and then using `shutil.move()` to replace the original file.  When the `.env` path is a symbolic link and the temp directory resides on a different filesystem than the target (a common configuration on Linux systems using tmpfs for `/tmp`), the following sequence occurs:  1. `shutil.move()` first attempts `os.rename()`, which fails with an `OSError` because atomic renames cannot cross device boundaries. 2. On failure, `shutil.move()` falls back to `shutil.copy2()` followed by `os.unlink()`. 3. `shutil.copy2()` calls `shutil.copyfile()` with `follow_symlinks=True` by default. 4. This causes the content to be written to the **symlink target** rather than replacing the symlink itself.  An attacker who has write access to the directory containing a `.env` file can pre-place a symlink pointing to any file that the application process has write access to. When the application (or a privileged process such as a deploy script, Docker entrypoint, or CI pipeline) calls `set_key()` or `unset_key()`, the symlink target is overwritten with the new `.env` content.  This vulnerability does not require a race condition and is fully deterministic once the preconditions are met.  ### Impact The primary impacts are to **integrity** and **availability**:  - **File overwrite / destruction (DoS):** An attacker can cause an application or privileged process to corrupt or destroy configuration files, database configs, or other sensitive files it would not normally have access to modify. - **Integrity violation:** The target file's original content is replaced with `.env`-formatted content controlled by the attacker. - **Potential privilege escalation:** In scenarios where a privileged process (running as root or a service account) calls `set_key()`, the attacker can leverage this to write to files beyond their own access level.  The scope of impact depends on the application using python-dotenv and the privileges under which it runs.   ### Proof of Concept  The following script demonstrates the vulnerability. It requires `/tmp` and the user's home directory to reside on different devices (common on systemd-based Linux systems with tmpfs).  ```python import os import sys import tempfile from dotenv import set_key  # Pre-condition: /tmp must be on a different device than the target directory. tmp_dev = os.stat(\"/tmp\").st_dev home_dev = os.stat(os.path.expanduser(\"~\")).st_dev assert tmp_dev != home_dev, \"Skipped: /tmp and ~ are on the same device (no cross-device move)\"  with tempfile.TemporaryDirectory(dir=os.path.expanduser(\"~\")) as workdir:     # File an attacker wants to overwrite     target = os.path.join(workdir, \"victim_config.txt\")     with open(target, \"w\") as f:         f.write(\"DB_PASSWORD=supersecret\\n\")      # Attacker pre-places a symlink at the path the application will use as .env     env_symlink = os.path.join(workdir, \".env\")     os.symlink(target, env_symlink)      before = open(target).read()      # Application writes a new key -- triggers the cross-device fallback     set_key(env_symlink, \"INJECTED\", \"attacker_value\")      after = open(target).read()      print(\"Before:\", repr(before))     print(\"After: \", repr(after))     print(\"Symlink target overwritten:\", target) ```  **Expected output:** ``` Before: 'DB_PASSWORD=supersecret\\n' After:  \"DB_PASSWORD=supersecret\\nINJECTED='attacker_value'\\n\" Symlink target overwritten: /home/user/tmp806nut2g/victim_config.txt ```  ### Remediation  The fix changes the `rewrite()` context manager in the following ways:  1. **Symlinks are no longer followed by default.** When the `.env` path is a symlink, `rewrite()` now resolves it to the real path before proceeding, or (by default) operates on the symlink entry itself rather than the target. 2. **A `follow_symlinks: bool = False` parameter** is added to `set_key()` and `unset_key()` for users who explicitly need the old behavior. 3. **Temp files are written in the same directory** as the target `.env` file (instead of the system temp directory), eliminating the cross-device rename condition entirely. 4. **`os.replace()` is used instead of `shutil.move()`**, providing atomic replacement without symlink-following fallback behavior.  Users are advised to upgrade to the patched version as soon as it is available on PyPI.  ### Timeline  | Date             | Event                                                                                                                                                                 | | ------------ | ---------------------------------------------------------------------------------------------------- | | 2026-01-09  | Initial report received from Giorgos Tsigourakos regarding a separate, unrelated issue also located in `rewrite()` | | 2026-01-10   | Co-maintainer acknowledged report, requested clarification                                                         | | 2026-01-11    | Initial report assessed as not exploitable and closed                                                              | | 2026-02-24  | Reporter identified new, distinct cross-device symlink attack vector with deterministic exploitation               | | 2026-02-26  | Co-maintainer confirmed vulnerability and shared draft patch                                                       | | 2026-02-26  | Reporter validated fix with monkeypatched PoC, proposed CVSS                                                       | | 2026-03-01   | Patch merged to main                                                                                               | | 2026-03-01   | Patched version released to PyPI                                                                                   | | 2026-04-20   | Advisory published                                                                                                 |  ### Patches  Upgrade to v.1.2.2 or use the patch from https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311.patch"}]}, {"name": "python-multipart", "version": "0.0.28", "vulns": []}, {"name": "pyyaml", "version": "6.0.3", "vulns": []}, {"name": "redis", "version": "7.4.0", "vulns": []}, {"name": "requests", "version": "2.33.1", "vulns": []}, {"name": "resend", "version": "2.30.1", "vulns": []}, {"name": "rich", "version": "15.0.0", "vulns": []}, {"name": "ruff", "version": "0.15.13", "vulns": []}, {"name": "scikit-learn", "version": "1.8.0", "vulns": []}, {"name": "scipy", "version": "1.17.0", "vulns": []}, {"name": "sentry-sdk", "version": "2.60.0", "vulns": []}, {"name": "six", "version": "1.17.0", "vulns": []}, {"name": "sniffio", "version": "1.3.1", "vulns": []}, {"name": "sortedcontainers", "version": "2.4.0", "vulns": []}, {"name": "soupsieve", "version": "2.8.3", "vulns": []}, {"name": "soxr", "version": "1.0.0", "vulns": []}, {"name": "sqlalchemy", "version": "2.0.49", "vulns": []}, {"name": "standardwebhooks", "version": "1.0.1", "vulns": []}, {"name": "starlette", "version": "0.50.0", "vulns": []}, {"name": "stripe", "version": "15.1.0", "vulns": []}, {"name": "structlog", "version": "25.5.0", "vulns": []}, {"name": "svix", "version": "1.93.0", "vulns": []}, {"name": "tenacity", "version": "9.1.4", "vulns": []}, {"name": "threadpoolctl", "version": "3.6.0", "vulns": []}, {"name": "tomli", "version": "2.4.1", "vulns": []}, {"name": "tomli-w", "version": "1.2.0", "vulns": []}, {"name": "tqdm", "version": "4.67.1", "vulns": []}, {"name": "types-deprecated", "version": "1.3.1.20260408", "vulns": []}, {"name": "types-python-dateutil", "version": "2.9.0.20260408", "vulns": []}, {"name": "types-pytz", "version": "2026.2.0.20260506", "vulns": []}, {"name": "typing-extensions", "version": "4.15.0", "vulns": []}, {"name": "typing-inspection", "version": "0.4.2", "vulns": []}, {"name": "urllib3", "version": "2.6.3", "vulns": [{"id": "CVE-2026-44431", "fix_versions": ["2.7.0"], "aliases": ["GHSA-qccp-gfcp-xxvc"], "description": "### Impact  When following cross-origin redirects for requests made using urllib3\u2019s high-level APIs, such as `urllib3.request()`, `PoolManager.request()`, and `ProxyManager.request()`, sensitive headers \u2014 `Authorization`, `Cookie`, and `Proxy-Authorization` (defined in `Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT`) \u2014 are stripped by default, as expected.  However, cross-origin redirects followed from the low-level API via `ProxyManager.connection_from_url().urlopen(..., assert_same_host=False)` still forward these sensitive headers.  ### Affected usage  Applications and libraries using urllib3 versions earlier than 2.7.0 may be affected if they allow cross-origin redirects while making requests through `HTTPConnection.urlopen()` instances created via `ProxyManager.connection_from_url()`.  ### Remediation  Upgrade to urllib3 version 2.7.0 or later, in which sensitive headers are stripped from redirects followed by `HTTPConnection`.  If upgrading is not immediately possible, avoid using this low-level redirect flow for cross-origin redirects. If appropriate for your use case, switch to `ProxyManager.request()`."}, {"id": "CVE-2026-44432", "fix_versions": ["2.7.0"], "aliases": ["GHSA-mf9v-mfxr-j63j"], "description": "### Impact  urllib3's [streaming API](https://urllib3.readthedocs.io/en/2.7.0/advanced-usage.html#streaming-and-i-o) is designed for the efficient handling of large HTTP responses by reading the content in chunks, rather than loading the entire response body into memory at once.  urllib3 can perform decompression based on the HTTP `Content-Encoding` header (e.g., `gzip`, `deflate`, `br`, or `zstd`). When using the streaming API since version 2.6.0, the library decompresses only the necessary bytes, enabling partial content consumption.  However, urllib3 before version 2.7.0 could still decompress the whole response instead of the requested portion in two cases: 1. During the second `HTTPResponse.read(amt=N)` call when the response was decompressed using the official [Brotli](https://pypi.org/project/brotli/) library. 2. When `HTTPResponse.drain_conn()` was called after the response had been read and decompressed partially (compression algorithm did not matter here).  These issues could cause urllib3 to fully decode a small amount of highly compressed data in a single operation. This could result in excessive resource consumption (high CPU usage and massive memory allocation for the decompressed data; CWE-409) on the client side.   ### Affected usages  Applications and libraries using urllib3 versions earlier than 2.7.0 may be affected when streaming compressed responses from untrusted sources in either of these cases, unless decompression is explicitly disabled:  1. A response encoded with `br` is read incrementally with at least two `HTTPResponse.read(amt=N)` or `HTTPResponse.stream(amt=N)` calls while using the official [Brotli](https://pypi.org/project/brotli/) library. 2. `HTTPResponse.drain_conn()` is called after response decompression has already started.   ### Remediation  Upgrade to at least urllib3 version 2.7.0 in which the library: 1. Is more efficient for reads with Brotli. 2. Always skips decompression for `HTTPResponse.drain_conn()`.  If upgrading is not immediately possible, the following workarounds may reduce exposure in specific cases: 1. For the Brotli-specific issue only, switch from [brotli](https://pypi.org/project/brotli/) to [brotlicffi](https://pypi.org/project/brotlicffi/) until you can upgrade urllib3; the official Brotli package is affected because of https://github.com/google/brotli/issues/1396. 2. If your code explicitly calls `HTTPResponse.drain_conn()`, call `HTTPResponse.close()` instead when connection reuse is not important.   ### Credits  The Brotli-specific issue was reported by @kimkou2024. `HTTPResponse.drain_conn()` inefficiency was reported by @Cycloctane."}]}, {"name": "uvicorn", "version": "0.47.0", "vulns": []}, {"name": "uvloop", "version": "0.22.1", "vulns": []}, {"name": "watchfiles", "version": "1.1.1", "vulns": []}, {"name": "websockets", "version": "16.0", "vulns": []}, {"name": "wrapt", "version": "2.1.2", "vulns": []}, {"name": "zipp", "version": "3.23.1", "vulns": []}], "fixes": []}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions