PI Desktop Security Features: Plugin Isolation and Policy Enforcement Explained

PI Desktop implements a defense-in-depth security model using Electron renderer sandboxing, declarative manifest policies, strict UI timeouts, and cryptographic version locks to isolate untrusted plugin code from the host system.

PI Desktop is an extensible desktop application framework that treats third-party plugins as potentially hostile code. The vastsa/PI-Desktop repository enforces this security posture through a layered architecture that combines process-level isolation with fine-grained access controls. Every plugin operates within a tightly restricted execution environment where network requests, filesystem operations, and UI interactions are explicitly permitted or denied by declarative policies.

Renderer Sandboxing and Process Isolation

PI Desktop launches all Electron renderer processes with sandbox: true to eliminate direct access to Node.js APIs and the host filesystem. This configuration is enforced in apps/desktop/electron/main/index.ts at line 2633, ensuring that UI code executes in a Chromium sandbox without the ability to spawn child processes or require native modules. The sandboxing prevents plugins from escaping the browser context to access operating system resources, establishing the first line of defense against code injection attacks.

Trusted Extension Framework and Lifecycle Controls

The trusted-extension framework defined in packages/shared/src/trusted-extensions.ts governs how extensions register commands, prompt users, and handle events. This layer introduces three critical safety mechanisms:

  • Handler Timeouts: The constant TRUSTED_EXTENSION_HANDLER_TIMEOUT_MS sets a hard limit of 30 seconds for command execution, preventing infinite loops from freezing the application.
  • UI Prompt Timeouts: TRUSTED_EXTENSION_PROMPT_TIMEOUT_MS enforces a 5-minute maximum lifetime for all user confirmation dialogs, ensuring that modal windows cannot persist indefinitely.
  • Kernel Version Lock: The TRUSTED_EXTENSION_KERNEL_VERSION constant ensures that sidecar extensions run only against specific, vetted core versions, preventing compatibility exploits.

Extensions are identified by real-path IDs and loaded once per session, with errors reported via TrustedExtensionDiagnostic objects for auditability.

Declarative Network and Filesystem Policies

PI Desktop requires plugins to declare their intended resource access in their manifests. These declarations are parsed and enforced at runtime by the policy engines in the plugin SDK.

Network Egress Controls

The packages/plugin-sdk/src/net-policy.ts module evaluates every outbound URL against a whitelist/blacklist declared in the plugin manifest's net section. The isNetUrlAllowed function checks requests against explicit allow and deny patterns before permitting network access.

{
  "name": "my-plugin",
  "version": "1.0.0",
  "net": {
    "allow": ["https://api.example.com", "https://static.example.org"],
    "deny": ["*"]
  }
}

This configuration blocks all network traffic except to the two specified domains. The * wildcard in the deny list functions as a default-deny fallback.

Filesystem Access Restrictions

The packages/plugin-sdk/src/fs-policy.ts module parses the fs section of the manifest to construct runtime permission sets. Plugins must specify read and write roots (such as userSelected or workspace) and glob patterns defining valid scopes.

{
  "fs": {
    "read": { "root": "userSelected", "scope": ["documents/**"] },
    "write": { "root": "workspace", "scope": ["output/**"] }
  }
}

Attempts to read outside documents/** or write outside output/** trigger policy violations and are rejected before reaching the operating system.

Remote Agent Control Protocol (RACP) Security

For remote management scenarios, packages/shared/src/racp.ts and packages/agent-host/src/agent-host.ts implement the Remote Agent Control Protocol. This subsystem governs how external agents request approvals, set session permissions, or affect other connected sessions.

The host-side policy can define approvalLifetimeMs values that automatically expire remote grants after a specified duration, protecting against long-lived elevated privileges from forgotten or compromised remote sessions.

// In agent-host.ts – when a remote session requests a grant
if (this.policy.approvalLifetimeMs) {
  const ttl = this.policy.approvalLifetimeMs;
  // Grant expires after `ttl` milliseconds
}

Runtime Policy Enforcement and Timeouts

When a plugin loads, packages/plugin-sdk/src/index.ts (lines 9-13) merges the plugin's manifest policies with host-wide constraints. Every network request and file operation is checked against this merged policy before execution.

UI interactions are further constrained by the timeout system in packages/shared/src/trusted-extensions.ts. When an extension triggers a user prompt, the renderer must receive a response within TRUSTED_EXTENSION_PROMPT_TIMEOUT_MS (300,000ms) or the request automatically expires.

import { trustedExtensionCommandId } from '@pi/shared/trusted-extensions';

// Send a confirm request to the renderer
desktop.sendUiRequest({
  sessionId,
  extensionId,
  extensionLabel,
  request: { kind: "confirm", title: "Delete file?", message: "Are you sure?" }
});

// Handle the response (must finish within TRUSTED_EXTENSION_PROMPT_TIMEOUT_MS)
desktop.onUiResponse((resp) => {
  if (resp.kind === "confirm") {
    // resp.value === true/false
  }
});

Summary

Frequently Asked Questions

How does PI Desktop prevent plugins from accessing the filesystem?

PI Desktop strips Node.js APIs from renderer processes through Electron sandboxing and requires plugins to declare filesystem scopes in their manifests. The fs-policy.ts module parses these declarations and rejects any operation outside the permitted root and scope boundaries before the request reaches the operating system.

What happens if a plugin hangs while waiting for user input?

All UI prompts are subject to TRUSTED_EXTENSION_PROMPT_TIMEOUT_MS (5 minutes) as defined in packages/shared/src/trusted-extensions.ts. If the user does not respond within this window, the promise automatically rejects, returning control to the host application and preventing indefinite modal locks.

Can plugins communicate with any server on the internet?

No. The net-policy.ts module enforces a default-deny posture. Plugins must explicitly whitelist domains in their manifest's net.allow array, and the isNetUrlAllowed function blocks any request not matching these patterns, including DNS rebinding attempts against internal IP ranges.

How does PI Desktop ensure extension compatibility with the core application?

The TRUSTED_EXTENSION_KERNEL_VERSION constant in packages/shared/src/trusted-extensions.ts creates a cryptographic lock between the extension and a specific core version. If the running kernel version does not match the extension's compiled target, the plugin is prevented from loading, mitigating API mismatch exploits.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →