Permissions & Security Flow
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Permissions & Security Flow in OpenWork is built on the core principle of Least Privilege, ensuring the system only works with folders the user authorizes and requires explicit approvals for sensitive actions. The architecture is "local-first" by default, utilizing the OS keychain for credentials and maintaining transparent audit logs for all security-relevant decisions.
Security is enforced through a two-layer model: the OpenWork UI layer, where users explicitly select allowed root folders via native pickers, and the OpenCode server layer, which intercepts and requests specific permissions as needed during task execution.
Sources: PRINCIPLES.md:12, PRINCIPLES.md:20-30, ARCHITECTURE.md:144-150
Security Architecture
OpenWork operates in two primary modes: Host Mode (where the engine runs locally on loopback) and Client Mode (where a remote device acts as a controller). Security in both modes relies on secure handshakes, token-based authentication, and explicit folder authorization.
Two-Layer Authorization Model
Security is not handled by a single component but rather through a coordinated effort between the UI and the underlying engine.
| Layer | Responsibility | Mechanism |
|---|---|---|
| OpenWork UI | Root Level Authorization | User selects allowed folders via native Tauri dialogs. |
| OpenCode Engine | Granular Action Permission | Intercepts tool calls and requests "Once", "Session", or "Always" access. |
| OpenWork Server | Write-Gatekeeping | All write operations are gated by a host approval token. |
Sources: ARCHITECTURE.md:28-36, ARCHITECTURE.md:144-155, packages/server/src/server.ts:600-605
Connection & Authentication Flow
When a client connects to a host, it must provide a pairing URL and a secure token. The system uses SHA-256 hashing for tokens and enforces Bearer token validation for all client-to-server requests.
The diagram above illustrates the handshake and token validation process between a client and the server.
Sources: packages/server/src/server.ts:114-130, packages/headless/src/cli.ts:400-410
Permission Decision Flow
Permissions are handled dynamically during a "Task Run." When an agent attempts a restricted tool call, an event is triggered that surfaces a permission request in the UI.
Permission Response Lifecycle
- Request Generation: The engine identifies a restricted action (e.g., writing to a file outside current scope).
- UI Interception: The UI subscribes to
client.event.subscribe()and detects the permission request. - User Decision: The user is presented with a modal showing the "why" and scope of the request.
- Reply Execution: The UI calls
client.permission.reply({ requestID, reply }).
Sources: PRODUCT.md:144-149, ARCHITECTURE.md:88-100
Approval Modes
The OpenWork server supports different approval configurations to balance security and developer velocity.
- Manual Mode: Default. Every write request requires a host to manually approve via the
/approvalsendpoint. - Auto Mode: Used primarily for local development. Automatically approves requests.
Sources: packages/server/src/server.ts:600-610, packages/headless/src/cli.ts:25-30
Folder Authorization & Path Security
OpenWork strictly enforces filesystem boundaries. A workspace is only authorized if it exists within the authorizedRoots defined in the server configuration.
This flowchart describes how a path is validated against authorized roots before access is granted.
Sources: packages/server/src/server.ts:585-598, ARCHITECTURE.md:144-155
Implementation Detail: Path Validation
The server resolves paths to their absolute form and checks if they start with an authorized root segment to prevent path traversal attacks.
// packages/server/src/server.ts:592-598
async function isAuthorizedRoot(workspacePath: string, roots: string[]): Promise<boolean> {
const resolvedWorkspace = resolve(workspacePath);
for (const root of roots) {
const resolvedRoot = resolve(root);
if (resolvedWorkspace === resolvedRoot) return true;
if (resolvedWorkspace.startsWith(resolvedRoot + sep)) return true;
}
return false;
}
Audit Logging & Transparency
Transparency is a core principle of the system. Every major decision and permission result is recorded in an exportable audit log.
Audit Entry Structure
An audit entry captures the "who, what, and when" of every significant action.
| Field | Description |
|---|---|
id | Unique short ID for the entry. |
actor | Information about who initiated the action (Host vs Remote Client). |
action | The type of action performed (e.g., config.patch, plugins.add). |
target | The resource affected (e.g., opencode.json). |
summary | A human-readable description of the event. |
timestamp | Epoch time when the event occurred. |
Sources: packages/server/src/server.ts:223-233, PRODUCT.md:66-73
Conclusion
The Permissions & Security Flow in OpenWork provides a robust framework for agentic workflows by combining strict filesystem scoping with real-time user oversight. By forcing explicit approvals for writes and maintaining detailed audit logs, OpenWork ensures that even complex, automated tasks remain under the final control of the user.