CVE-2026-42301
pyp2spec: Command injection via unescaped macros in PyPI package metadata.
- CVSS 7.8
- CWE-20
- Input Validation and Sanitization
- Remote
pyp2spec generates working Fedora RPM spec file for Python projects. Prior to version 0.14.1, pyp2spec was writing PyPI package metadata (e.g. the summary field) into the generated spec file without escaping RPM macro directives. When a packager then runs rpmbuild, those directives get evaluated, so a malicious package can execute arbitrary commands on the build machine. This issue has been patched in version 0.14.1.
- CWE
- CWE-20
- CVSS base score
- 7.8
- Published
- 2026-05-09
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- pyp2spec
- Fixed by upgrading
- Yes
Solution
Upgrade pyp2spec to version 0.14.1 or later.
Vulnerable code sample
import sys
def generate_vulnerable_spec(package_metadata):
"""
This function represents the vulnerable logic of pyp2spec.
It directly injects metadata into a template without escaping.
"""
spec_template = """Name: python-{name}
Version: {version}
Release: 1%{?dist}
Summary: {summary}
License: {license}
%description
This is a spec file generated for {name}.
%prep
%setup -q
%build
%py3_build
%install
%py3_install
%files
# The files would be listed here
"""
# The vulnerability is here: direct, unescaped string formatting.
# A malicious 'summary' field containing an RPM macro will be
# embedded directly into the output.
spec_content = spec_template.format(
name=package_metadata.get("name"),
version=package_metadata.get("version"),
summary=package_metadata.get("summary"),
license=package_metadata.get("license"),
)
return spec_content
# 1. Simulate malicious metadata from a compromised PyPI project.
# The 'summary' field contains an RPM macro that executes a shell command.
malicious_metadata = {
'name': 'malicious-package',
'version': '1.0.0',
'summary': 'A helpful library. %{expand:%%(touch /tmp/pwned)}',
'license': 'MIT',
}
# 2. Run the vulnerable generator function.
vulnerable_output = generate_vulnerable_spec(malicious_metadata)
# 3. Write the output to a file. In a real attack, a user would
# then run `rpmbuild -ba malicious.spec`, triggering the command execution.
with open("malicious.spec", "w") as f:
f.write(vulnerable_output)Patched code sample
def escape_rpm_macros(text: str) -> str:
"""
Escapes RPM macros in a string by replacing all occurrences of '%' with '%%'.
This prevents rpmbuild from interpreting strings like '%{...}' as executable
directives.
"""
return text.replace("%", "%%")
# Example of how the fix is applied:
# Malicious metadata from a PyPI package
malicious_summary = "A very helpful package %{!?foo:bar} %{lua:os.execute('touch /tmp/pwned')}"
# In the vulnerable version, this would be written directly to the .spec file:
# Summary: A very helpful package %{!?foo:bar} %{lua:os.execute('touch /tmp/pwned')}
# With the fix, the metadata is sanitized before being written
safe_summary = escape_rpm_macros(malicious_summary)
# The sanitized string is written to the .spec file, which is now safe:
# Summary: A very helpful package %%{!?foo:bar} %%{lua:os.execute('touch /tmp/pwned')}
# rpmbuild will now treat '%%' as a literal '%' and will not execute the macro.Payload
%(touch /tmp/pwned)
Cite this entry
@misc{vaitp:cve202642301,
title = {{pyp2spec: Command injection via unescaped macros in PyPI package metadata.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-42301},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-42301/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
