Status: Met
compliance-trestle is a software project that produces an OSCAL authoring and validation CLI tool. Secure design principles apply in full. The sections below map each principle to concrete, verifiable evidence in the codebase.
- Fail-Safe Defaults
Access decisions should deny by default; installation should be secure by default.
Evidence Location
HTTPS-only remote access. HTTP is unconditionally rejected; only https:// and sftp:// are permitted. security.py:149-162
Loopback, link-local, cloud-metadata endpoints always blocked. ALWAYS_BLOCKED_NETWORKS and METADATA_HOSTNAMES apply regardless of configuration. security.py:50-77
Private-IP blocking is an opt-in relaxation. SigningManifestDiscovery sets block_private_ips = True by default; callers must explicitly pass allow_private_uris=True. signing_manifest_discovery.py:45-57
Workspace-boundary enforcement is on by default. validate_local_file_path requires paths inside the workspace root unless the caller explicitly passes allow_outside_workspace=True. security.py:446-549
No-overwrite default for signed output. trestle sign raises TrestleError if the output file already exists and --overwrite was not requested. signing.py:119-147
Bounded resource defaults. Maximum discovered artifacts (1,000), depth (64), per-file size (50 MiB), and aggregate remote size (500 MiB) are fixed constants that prevent resource-exhaustion. signing_manifest_discovery.py:34-39
Safe YAML loading by default. YAML(typ='safe') is used everywhere YAML is parsed, preventing arbitrary Python-object construction. file_utils.py:223-237
Defusedxml for XML parsing. The defusedxml library is a declared dependency, blocking XML-bomb, XXE, and entity-expansion attacks. pyproject.toml:35-55
Default packaged config contains no credentials or permissive settings. config.ini
2. Complete Mediation
Every access that might be limited must be checked for authority; checks must be non-bypassable.
Evidence Location
Double validation for remote fetches. URLSecurityValidator.validate_url() is called both in the fetcher constructor and immediately before requests.get() in _do_fetch(), mitigating DNS-rebinding/TOCTOU attacks. cache.py:264-337
Every remote URL is fully parsed, DNS-resolved, canonicalized, and checked against blocked networks, metadata hostnames, and optional domain allowlist. security.py:80-129
IPv4-mapped IPv6 addresses are canonicalized to their IPv4 form before network checks, preventing bypass via ::ffff:127.0.0.1. security.py:216-230
Path-traversal checks at every file access boundary (URL paths for cache, resolved cache paths, trestle:// URIs, local workspace paths, signing output paths, manifest artifact paths). security.py:306-549, signing_manifest.py:213-236
Cryptographic authority verification. Signature verification checks DSSE envelope structure, in-toto statement type, predicate type, canonicalization algorithm, digest algorithm, and the SHA-256 digest of the canonical document — any mismatch raises an error. signing.py:182-232
Constant-time digest comparison (hmac.compare_digest) for signed package verification, preventing timing-oracle attacks. signing_manifest.py:136-191
Validated Pydantic model loading wraps all OSCAL model deserialization; validation errors are surfaced, not silently accepted. trestle_base_model.py:27-66
Symlink rejection at both signing output and remote-artifact vendoring paths. signing.py:119-147, signing_manifest_discovery.py:197-233
Cycle detection and recursion-depth limiting in manifest dependency discovery, with finally guaranteeing stack cleanup. signing_manifest_discovery.py:70-97
3. Economy of Mechanism (Keep It Simple)
Evidence Location
Dedicated security.py module centralizes all SSRF, path-traversal, and sensitive-file logic in one well-named place, making the security surface easy to audit. remote/security.py
Normalized exception handling converts all security violations to TrestleError, providing a single control-flow path. Throughout
4. Least Privilege / Credential Hygiene
Evidence Location
Credentials must be environment-variable references (mustache template syntax). Literal credential strings are rejected at parse time. cache.py:275-311
Documented in internal spec: Credentials MUST NOT be stored in cleartext. caching_spec.md:131-164
5. Defense-in-Depth / Input Validation
Evidence Location
SSTI prevention. Jinja2 template delimiters ({{, }}) in OSCAL prose are neutralized before output, applied at every prose-writing boundary. ssp_io.py:36-48
Security-tested Jinja2 sandbox with autoescape=True and tests confirming RCE-payload blocking. tags_security_test.py
Directory/task name validation rejects absolute paths, traversal segments, hidden names, reserved names, and file-extension names. file_utils.py:95-133
Sensitive-file denylist blocks access to credentials, SSH keys, cloud configuration, /proc, /sys, logs, and DB directories even when outside-workspace access is explicitly granted. security.py:446-549
Reject-unknown-fields validation in manifest parsing. signing_manifest.py:213-236
Bandit (flake8-bandit S rules) enabled in Ruff linting, providing static security analysis on every CI run. pyproject.toml:205-220
6. Open Design / Documented Security Properties
Evidence Location
CLI tutorial documents SSRF protections, limit constants, signature-verification steps, and HTTPS-only policy. docs/tutorials/cli.md:656-696
Caching spec documents HTTPS requirement and credential-handling policy. internal_spec_documents/caching_spec.md
Summary
The project implements all applicable secure-design principles from the know_secure_design framework:
Fail-safe defaults — deny-by-default for private networks, symlinks, path traversal, HTTP, and unknown fields; secure resource limits; safe parsers out of the box.
Complete mediation — every remote fetch, local file access, path lookup, and cryptographic verification goes through a non-bypassable validation layer before the operation executes.
Economy of mechanism — security logic is consolidated in dedicated, auditable modules.
Least privilege — credentials are env-var references; explicit opt-ins required for any relaxation.
Defense-in-depth — layered validation (URL → DNS → IP → path → size → type → signature), SSTI neutralization, sandbox testing, and static security linting.