This document describes the security architecture of the Ledger application, including Electron sandbox configuration, IPC security, command injection prevention, and plugin permission system.
Ledger uses Electron's security best practices with explicit configuration in lib/main/app.ts:
Key settings applied:
- Sandbox is enabled to keep renderer processes constrained.
- Context isolation is enabled so preload runs in a separate context.
- Node.js integration is disabled in renderers and workers.
- Web security (same-origin policy) is enforced.
Why these settings matter:
sandbox: true: Enables Chromium's OS-level sandboxing, restricting what the renderer process can accesscontextIsolation: true: Runs preload scripts in an isolated context, preventing renderer code from accessing Node.js APIs or modifying preload globalsnodeIntegration: false: Prevents renderer code from accessing Node.js APIs directlywebSecurity: true: Enforces same-origin policy, preventing cross-origin requests
The preload script (lib/preload/preload.ts) performs a runtime check to warn if context isolation is unexpectedly disabled.
The application uses a restrictive CSP in app/index.html:
The policy restricts scripts to self, limits styles to self (plus inline for app styles), and only allows images from self, data:, and res:.
This prevents:
- Loading scripts from external sources
- Inline script execution (except trusted preload)
- Loading resources from unauthorized origins
All renderer-to-main process communication uses ipcRenderer.invoke() with typed channels:
Patterns:
- Preload exposes a narrow, versioned API surface via
contextBridge(lib/preload/preload.ts). - Main process handlers validate all inputs with Zod schemas (
lib/conveyor/schemas,lib/conveyor/handlers).
IPC handlers use safe error serialization (lib/utils/error-helpers.ts) to prevent leaking sensitive information:
Errors are normalized to safe, serializable messages before crossing the process boundary.
The application uses safeExec() (lib/utils/safe-exec.ts) for all shell commands:
It always uses argv-style invocation (no shell interpolation) and sets explicit timeouts to reduce risk.
Key security feature: shell: false ensures arguments are passed directly to the process without shell interpretation, preventing injection attacks.
Validated against strict npm naming rules to prevent shell metacharacters and traversal.
Validated against strict HTTPS/SSH patterns to prevent command substitution and malformed URLs.
File path operations validate against directory traversal attacks: Paths are normalized, checked for traversal sequences, and required to be absolute before use.
| Operation | Protection Method |
|---|---|
| Plugin git clone | simple-git library (no shell) |
| NPM pack | safeExec + validation |
| PR create/comment | safeExec (args array) |
| PR merge | safeExec (args array) |
| Open URL | safeExec (URL as single arg) |
| Worktree creation | Path traversal validation |
Permissions are explicit and granular, including: git:read, git:write, fs:read, fs:write, network, shell, clipboard, and notifications.
- Plugin declares required permissions in manifest
- During activation,
pluginLoader.requestPermissions()is called - UI displays
PermissionDialogwith risk levels - User approves/denies specific permissions
- Approved permissions stored in
pluginRegistry PluginAPImethods check permissions before execution
Plugin API methods in lib/plugins/plugin-context.ts check permissions:
Calls are gated at the API boundary so unapproved permissions are denied before any side effects.
- Built-in plugins: Auto-approved (trusted source)
- Local plugins: Require user approval
- External plugins (git/npm): Require user approval + high-risk warning
-
Never use string interpolation for shell commands
- Use argv arrays with
safeExec(no shell interpolation).
- Use argv arrays with
-
Always validate external input
- Validate user input against strict patterns before executing commands.
-
Use Zod schemas for IPC validation
- Enforce input shapes at IPC boundaries with Zod.
-
Check permissions in plugin API methods
- Require explicit permissions before any privileged action.
Run the validation test suite:
npm test -- tests/validation.spec.ts
Tests cover:
- NPM package name validation
- Git URL validation
- Safe execution patterns
- Error serialization
If you discover a security vulnerability, please report it privately to the maintainers rather than opening a public issue.