VAITP Dataset

← Back to the dataset

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.

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 ::