Skip to content

Security model

PAM Desktop treats the frontend as trusted application code but still exposes no ambient native authority. Dangerous operations remain behind a typed Rust boundary declared by PHP policy.

trusted local UI
HTML / CSS / JavaScript
│ commands, events, named APIs
│ exact origin + ephemeral token
Rust host
Winit ─ Servo ─ loopback gateway
│ │ │
│ │ ├── supervised Rust plugin processes
│ │ └── interruptible background scheduler
│ │
│ typed effects / bounded JSON lines
PAM worker
PHP 8.4

PAM core owns the PHP Embed runtime. The desktop package owns application policy. The protocol crate owns envelopes and integer contracts. The Rust shell owns Servo, Winit, gateway, native adapters, and operating-system handles.

The local gateway:

  • binds to a random port on 127.0.0.1;
  • generates a cryptographically random 256-bit token;
  • requires the exact origin and token for command and native requests;
  • compares tokens without an early content exit;
  • verifies the source window;
  • restricts navigation to the gateway origin;
  • canonicalizes assets under the public root;
  • sets no-store, nosniff, and a restrictive Content Security Policy; and
  • freezes the injected API and its nested namespaces.

The gateway is not a public server.

Filesystem roots are opened once as capability-scoped directories through cap-std.

Requests accept only relative paths without ... Final symbolic links are rejected, and capability-based traversal prevents intermediate links from escaping a root.

Selected and dropped files become opaque process-lifetime grants. Dialogs return names, integer kinds, integer access levels, and grant IDs—not native paths.

Host and PHP worker exchange one JSON object per line. A message is limited to 1 MiB and correlated by a monotonically increasing unsigned request ID.

Sequential integer variants include:

Contract Values
Message kind 1 request, 2 response
Response status 1 success, 2 failure
Window theme 1 system, 2 light, 3 dark
Effect kind 1 title, 2 visibility, 3 close, 4 focus
File access 1 read, 2 write, 3 read-write
File entry 1 file, 2 directory
Notification urgency 1 low, 2 normal, 3 critical

Protocol 6 extends effect kinds through tray visibility and adds sequential integer contracts for update policy/state, menu items, tray close behavior, shortcut state, and job overlap. Rust plugins use their own stable protocol 1.

Protocol version is checked on every response. A mismatch, malformed envelope, wrong request ID, oversized line, invalid kind, or failure without an error terminates that invocation explicitly.

Commands, PHP events, and background jobs run one at a time through a worker mutex. Axum can serve transport concurrently, while the single Zend worker stays deterministic. Each Rust plugin has an independent supervised process and bounded protocol.

When an invocation times out, is cancelled, crashes the worker, or corrupts the protocol, the host kills and reaps that worker and starts another generation.

PAM does not retry the interrupted command. A handler may have committed a side effect before failing. Applications must design their own idempotency and recovery semantics.

Asset changes reload WebViews. PHP and Composer changes restart the worker, validate a complete new bootstrap, and atomically reconfigure windows.

Invalid reloads keep the host alive and emit pam.dev.error.

Capability changes prepare a complete replacement native service before the swap. A successful replacement expires old grants. Invalid roots keep the current service active.

PAM Desktop intentionally does not support:

  • loading arbitrary remote pages inside a privileged application window;
  • an unrestricted shell or process API;
  • arbitrary ambient filesystem paths in browser code;
  • executing package-provided native scripts at runtime; or
  • hiding native authority inside an untyped generic bridge.

New capabilities should be named, typed, bounded, validated on both sides, and disabled by default.

Public API 1, worker protocol 6, and Rust plugin protocol 1 are compatibility gated on Linux x86-64. Servo 0.4 and platform graphics stacks still evolve, and Rust plugins are trusted native executables rather than operating-system sandboxes. Run an application-specific security review, update rollback test, and target-distribution qualification before broad consumer release.