Security
Security Model
OXP's threat model, defense layers, and what makes it the most secure extension platform.
Security is OXP's #1 design priority and its biggest competitive advantage over npm-style and VS-Code-Marketplace-style ecosystems. This page documents the complete threat model, current controls, and known gaps.
Design Principle
The daemon — not the SDK, not the webview — is the trust boundary. Every method call is re-authorized. Every handle is unforgeable. Every sensitive prompt is OS-native (never webview-rendered). Even a benign extension's webview is assumed compromised in the threat model.
Threat Model
Assets Protected
- The end-user's machine (filesystem, secrets, network, processes)
- The end-user's identity (auth tokens, SSO sessions)
- The publisher's identity (signing keys, publish tokens)
- The registry's integrity (bundle bytes, version history)
- The supply chain (source → build → sign → publish → install → run)
Adversaries
| Adversary | Capability | Motivation |
|---|---|---|
| Malicious author | Publishes a crafted .oxp | Steal data, crypto-mine, ransomware |
| Account hijacker | Steals a publisher's token | Push malicious update |
| Typosquatter | Registers @strlpe/checkout | Trick users into installing |
| Network attacker | MitM between host and registry | Swap bundle bytes |
| Compromised registry | DB + storage write access | Replace bundles, forge versions |
Defense Layers
Layer 1: WASI Sandbox
Extension code runs as a WASI Preview 2 component — no DOM, no Node.js, no syscalls. The only way to interact with the host is through WIT-typed imports mediated by the capability broker.
A Wasm component cannot:
- Read or write files without
fs.read/fs.writepermission - Make network requests without
net.fetchpermission - Access the clipboard, secrets, or terminal without explicit grants
- Fork processes — there is no
oxp:host/shellinterface in v1 - Import symbols the manifest didn't declare
Layer 2: Install-Time Permission Prompts
Before any extension runs, the user sees every requested capability with:
- The capability name and description
- The scope (which files, which URLs)
- The author's rationale
- Allow All / Customize / Deny options
Grants are persisted per (publisher, slug). On updates, only new permissions trigger re-prompting.
Layer 3: Cryptographic Signing
Every bundle is Ed25519-signed at pack time. The host re-verifies on install — zero trust toward the registry. Content-addressable bundles (SHA-256 of uncompressed tar) make tampering detectable.
Layer 4: TOFU Key Pinning
On first install from a publisher, the host records their public key in ~/.oxp/trust.json. Subsequent installs from the same publisher must use the same key. A different key triggers KEY_PINNING_VIOLATION — the install is blocked.
The registry also pins keys server-side on first publish.
Layer 5: Scoped Tokens
Publish tokens are scoped (publish:@handle/* or per-package) and expire after 90 days by default. The rotation endpoint provides a 5-minute grace window for in-flight publishes.
Layer 6: Bundle Policy Enforcement
assertBundlePolicy runs at both CLI pack and registry upload:
- **
ui-v1bundles** — no executable code allowed (no .js, .ts, .wasm, .sh, .exe, etc.) - **
component-v1bundles** — only a signed.wasm+.wit - Verified-only capabilities —
terminal.*andprocess.killdenied to unverified publishers - Unknown permissions — rejected by catalog validation
Layer 7: CSP for Webviews
Every rendered webview gets strict Content Security Policy:
default-src 'none'- Per-render nonce for scripts
connect-src 'none'frame-ancestors 'none'- No inline scripts
Layer 8: Resource Limits
Per-call wall-clock cap (default 100ms) prevents runaway components. Memory cap (default 64 MiB) bounds resource usage. Exceeding limits disposes the instance.
What's Safe Today
- Building and publishing your own extensions
- Installing extensions from publishers you personally trust
- Using
ui-v1declarative mode (no code execution path) - Relying on the WASI sandbox to contain honest mistakes
Known Gaps
- No publisher domain verification yet (Phase B)
- No bundle static analysis beyond policy checks (Phase B)
- No revocation mechanism for known-bad bundles (Phase C)
- No reserved namespace enforcement (Phase B)
- Wall-clock time limits only — real wasmtime fuel coming in Phase B