Threat model¶
Security objective¶
Execute an untrusted Monty Python program against a virtual workspace, decide whether its exact resulting transaction is allowed, and apply only that transaction through a trusted committer without exposing unauthorized host data or mutation paths.
Assets¶
- Workspace file integrity, confidentiality, names, metadata, and permissions.
- Protected files and secret material.
- Immutable snapshots, blobs, transaction digests, approval decisions, and receipts.
- Checksummed bounded transaction logs, immutable approval artifacts, and commit journal.
- Host resources: CPU, memory, descriptors, disk, output, and wall-clock time.
- Rust/Python API semantic parity.
- Dependency and release provenance.
Trust boundaries¶
| Component | Trust level | Notes |
|---|---|---|
| User goal | trusted intent, untrusted data | It constrains approval but may contain hostile text. |
| Main agent and generated program | untrusted | It may deliberately attempt escape, exfiltration, or exhaustion. |
| Python caller/PyO3 inputs | untrusted | Python cannot grant capabilities or bypass native validation. |
| Monty interpreter/worker | isolated execution component | It receives no raw host mount and is discarded after unsafe termination. |
| Configured worker executable | trusted installation input | Exact Monty version is checked; choosing a replacement binary grants native-code authority. |
| VirtualFs and deterministic policy | trusted security core | Complete mediation and one filesystem semantics live here. |
| Fresh judge | advisory/separate principal | It cannot reverse deterministic deny. |
| Transaction store | trusted state | CAS transitions enforce single-use commit. |
| Committer | smallest trusted host writer | It alone may mutate the real workspace. |
| External concurrent process | adversarial race source | Revalidation must detect dependency changes. |
| Third-party dependencies | supply-chain risk | Exact pins and continuous advisory/license/source checks apply. |
Attacker capabilities¶
Assume an attacker can:
- control Monty source code and input paths,
- use
.., absolute paths, platform separators, symlinks, rename chains, and races, - enumerate directories and condition outputs on secret data,
- request huge reads/writes/output or infinite computation,
- crash a worker or process at any commit boundary,
- replay, duplicate, reorder, or mutate transaction/approval identifiers,
- call public Rust or Python APIs with malformed values,
- trigger Python exceptions, finalization, threads, or interpreter shutdown,
- race the workspace between snapshot, approval, revalidation, and commit,
- exploit a vulnerable transitive dependency if one is present.
Assume the attacker cannot already execute arbitrary host-native code in the trusted VSH process. If raw host shell/filesystem tools are simultaneously available, VSH is not a complete security boundary.
Primary threats and controls¶
Host escape and confused paths¶
Threats: absolute paths, parent traversal, separator ambiguity, symlink/junction races, rename escape, and time-of-check/time-of-use gaps.
Controls:
- validated
VPathis relative and normalized, - capability-rooted descriptor access in the committer,
- no path resolution fallback to ambient process CWD,
- symlink policy applied before data exposure and again at commit,
- adversarial platform/path tests.
Confidentiality and output exfiltration¶
Threats: reading .env, keys, credentials, protected metadata, or encoding secrets into
stdout, errors, diffs, and receipts.
Controls:
- pre-call read capability policy,
- default-deny protected patterns,
- output and error payload budgets,
- compact receipts and artifact handles,
- redaction is defense-in-depth, not permission to perform the read.
Virtual/host semantic divergence¶
Threats: simulator predicts one effect while a distinct executor performs another; recursive and rename descendants are incompletely represented.
Controls:
- one VirtualFs implementation,
- canonical diff derived from final virtual state,
- committer applies the diff rather than replaying the original program,
- property tests against an independent filesystem model,
- post-commit expected-state verification.
Stale approval and replay¶
Threats: approval reused for different bytes/state, double execution, concurrent token use, or approval after workspace drift.
Controls:
- approval binds transaction digest, base snapshot, code hash, policy result, and diff,
- persisted state-machine CAS reservation,
- ReadSet/WriteSet revalidation,
- single-use commit transition,
- expiry where external approval is used.
Partial commit and crash consistency¶
Threats: process death after staging, first rename, deletion, verification, state-log compaction, or before transaction-state finalization leaves undefined host state.
Controls:
- staging/quarantine,
- durable commit journal,
- two alternating state logs selected by a fixed-size double-buffered control record,
- compacted log synchronization before the control generation can become active,
- idempotent recovery protocol,
- fault injection at every journal boundary,
- post-commit verification before final state.
Resource exhaustion¶
Threats: infinite computation, recursive trees, giant output, many OS calls, descriptor exhaustion, blob/overlay growth, and worker poisoning after a limit.
Controls:
- wall time, memory, calls, bytes, entries, output, and overlay budgets,
- bounded data structures and receipt sizes,
- per-runtime count and encoded-byte ceilings for process-local preview artifacts,
- discard workers after limit/panic,
- no unbounded queues or process-global serialization.
PyO3 boundary failure¶
Threats: panic unwinds through FFI, GIL held during long work, borrowed Python data outlives the GIL, Python exception interrupts transaction cleanup, or Python widens capability configuration.
Controls:
- catch/map panic before the FFI boundary and fail closed,
- own/validate data before releasing the GIL,
- keep Python objects outside the native hot path,
- native transaction guard performs cleanup regardless of Python exception,
- validate Python-result compatibility before artifact persistence or reservation so a known conversion failure cannot occur after auto-commit,
- parity and concurrency tests through both language surfaces.
Supply chain¶
Threats: abandoned crate, compromised release, known advisory, yanked version, malicious feature/default dependency, source substitution, or unreviewed lockfile drift.
Controls:
- deny-by-default admission records,
- exact version pins and committed lockfile,
- crates.io/workspace sources only,
- minimal features,
cargo auditandcargo deny,- explicit dependency update reviews,
- release provenance and built-artifact tests.
Security test families¶
- Host containment: absolute/parent/symlink/rename/mount escape.
- Destructive virtual execution: recursive delete changes only overlay before commit.
- Recursive correctness: final state and canonical diff include descendants exactly.
- Snapshot consistency: lazy reads become immutable or mark the transaction stale.
- Approval integrity: any transaction component change invalidates approval.
- Double commit: concurrent second reservation fails before host mutation.
- Worker crash: no host effect and worker is not reused.
- Secrets: denied bytes never reach Monty, Python, stdout, error, artifact, or receipt.
- Recovery: every injected crash boundary converges to a defined recoverable state.
- FFI parity: Rust/Python decisions, errors, receipts, and side effects match.
Explicit non-goals¶
- Protecting a host where the same agent also has unrestricted shell/filesystem access.
- Detecting all malicious intent or proving user-request semantic correctness.
- Providing a full OS/container sandbox for network, processes, devices, or syscalls not exposed by the supported typed Monty surface.
- Guaranteeing that no undiscovered dependency vulnerability exists.
- Preventing a privileged host administrator from modifying VSH state.