[security] fix(payloads): harden payload artifact paths#57
[security] fix(payloads): harden payload artifact paths#57Hinotoi-agent wants to merge 1 commit into
Conversation
|
@microsoft-github-policy-service agree |
|
Thanks for this @Hinotoi-agent and for the care that went into it, shared validator, thorough tests, everything green. After reviewing it against how RAMPART actually constructs and uses payloads, I'm going to close this PR as-is, but there's a piece of it I'd genuinely like to see come back as a focused follow-up, so I've written up the reasoning and a suggested scope below. The central change, validating That said, the load-side hardening is a real improvement and I'd like to take it, when deserializing a persisted collection, rejecting artifact references that are absolute, contain Would you be up for opening a new PR with just that? A scope that keeps it easy to accept:
Thanks again, the deserialization instinct is the right one, and I'll happily review the narrower version. |
|
Thanks for the detailed review and suggested scope. I opened the focused follow-up here: #106 It keeps only the load-time artifact containment path in |
Summary
This PR hardens how RAMPART handles payload identifiers and persisted payload artifacts before they are embedded into local artifact paths or OneDrive upload names.
Payload IDs and serialized artifact paths are now constrained to filename-safe, collection-local values. The patch rejects unsafe IDs at payload construction time, validates artifact copy destinations before writing, validates deserialized artifact references before loading, and applies the same payload ID boundary before constructing OneDrive upload paths.
Security issues covered
payloads.jsonlartifact reference could point outside the collection'sartifacts/directory.artifacts/...paths, reject..and absolute paths, and resolve/contain paths under the collection artifacts directory.Before this PR
Payload.idvalues were accepted without a filename/path safety boundary.payload.id.artifacts/.payload.idinto a Graph path-addressed filename.After this PR
.,_, and-..and..are rejected explicitly.artifacts/directory.artifacts/...paths and must not contain traversal segments.Why this matters
Payload collections are persisted to disk and may include binary artifacts. If a payload source, generated collection, or persisted JSONL record is treated as data but can influence filesystem paths, it can cross from payload content into host file placement or host file reads.
Enforcing a narrow filename-safe payload ID format and resolving artifact paths under the collection artifact root keeps payload data inside the intended storage boundary.
Attack flow
Affected code
rampart/core/types.pyrampart/core/payload_ids.pyrampart/payloads/_store.pyrampart/surfaces/onedrive.pyRoot cause
CVSS assessment
Issue: payload artifact path containment bypass
CVSS v3.1: 7.1 High
Vector:
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:NRationale: exploitation requires the ability to introduce or load a crafted payload collection or payload definition in the local RAMPART execution context. If reached, the vulnerable path construction can cross the intended artifact boundary and affect confidentiality or integrity of local files addressed by the running process.
Safe reproduction steps
On vulnerable code, a regression test can construct a payload with an ID containing traversal or load a
payloads.jsonlrecord whoseartifactfield points outsideartifacts/.Examples covered by the tests in this PR:
{"id":"safe","content":"x","format":"text","metadata":{},"artifact":"../outside.pdf"}Expected vulnerable behavior
Before the fix, unsafe payload IDs or serialized artifact references could reach path construction. Depending on the operation, this could place an artifact outside the expected directory or resolve a loaded artifact reference outside the collection's
artifacts/root.After the fix, these inputs raise
ValueErrorbefore file copy, artifact load, or OneDrive path construction proceeds.Changes in this PR
rampart.core.payload_ids.validate_payload_id()as the shared payload ID safety boundary.Payload.__post_init__()and OneDrive upload path construction..., non-artifacts/paths, and symlink escapes.Files changed
rampart/core/payload_ids.py,rampart/core/types.pyrampart/payloads/_store.pyrampart/surfaces/onedrive.pytests/unit/payloads/test_payload_store_security.py,tests/unit/surfaces/test_onedrive_security.pyMaintainer impact
This is intentionally narrow. Existing payload IDs that already use simple filename-safe IDs continue to work. Payload IDs containing path separators, Graph path delimiters, control characters, empty strings, or traversal-only segments are now rejected early with
ValueError.The persisted artifact format remains
artifacts/<filename>for valid existing collections.Fix rationale
The safest boundary is to prevent payload IDs from being path-like at all, then still perform resolved-path containment checks at the filesystem boundary. This keeps the API contract simple while preserving defense in depth for deserialized data that may come from disk.
Type of change
Test plan
Commands run locally:
Results:
14 passed462 passed0 errors, 0 warnings, 0 informationsDisclosure notes
This PR is limited to hardening payload ID and artifact path handling in the local payload store and OneDrive upload path construction. It does not claim to change unrelated payload generation, model behavior, or broader surface authentication semantics.