compliance-trestle Profile Import has an Arbitrary File Read via trestle:// URI and Relative Path Traversal
Date: 2026-05
Affected: pip/compliance-trestle, pip/compliance-trestle
Attack vector: path-traversal
Category: vulnerability-disclosure
Severity: Medium
CVE: CVE-2026-45774
CWE: CWE-22

## Summary The compliance-trestle library's profile import mechanism resolves `trestle://` URIs and relative file paths by joining them with `trestle_root` and calling `.resolve()`, but performs **no boundary check** to ensure the resolved path stays within the trestle workspace. An attacker can craft a malicious OSCAL profile YAML with `imports[].href` containing path traversal sequences to read arbitrary files from the server filesystem. Three attack vectors confirmed: 1. **PT-001:** `trestle://../../etc/passwd` — via trestle:// URI scheme 2. **PT-002:** `../../etc/passwd` — via relative path in href 3. **PT-003:** back_matter rlinks with traversal paths **Preconditions:** Victim must import/resolve an attacker-controlled OSCAL profile YAML. ## Affected Component **Repository:** https://github.com/IBM/compliance-trestle **File:** `trestle/core/remote/cache.py` (lines 175-179) **File:** `trestle/core/resolver/_import.py` (line 104) **Version:** v4.0.2 (latest as of 2026-04-30) ## Vulnerable Code ### cache.py:175-179 — LocalFetcher (trestle:// URI handling) ```python class LocalFetcher(FetcherBase): def __init__(self, trestle_root: pathlib.Path, uri: str) -> None: super().__init__(trestle_root, uri) # ... elif uri.startswith(const.TRESTLE_HREF_HEADING): uri = str(trestle_root / uri[len(const.TRESTLE_HREF_HEADING) :]) self._abs_path = pathlib.Path(uri).resolve() # ❌ NO boundary check — .resolve() follows


Mitigations:

Architectural layers (MAESTRO):