This document explains the security model, permissions, and considerations for users who clone and run CoWork OS on their machines.
CoWork OS is an AI-powered task automation tool that can execute actions on your behalf. By design, it has capabilities that require careful consideration:
- Execute shell commands
- Read and write files
- Browse the web
- Connect to external APIs
All of these capabilities are consent-based and sandboxed where possible.
Each workspace you create has configurable permissions:
| Permission | Description | Default |
|---|---|---|
| Read | Read files within the workspace | Enabled |
| Write | Create and modify files | Enabled |
| Delete | Remove files (requires approval) | Disabled |
| Shell | Execute shell commands (requires approval) | Disabled |
Recommendation: Only enable shell and delete permissions for workspaces where you trust the AI to perform those operations.
Certain operations always require explicit user approval before execution:
- Shell commands: You see the exact command before it runs
- File deletion: Confirmation required before removing files
- Sensitive operations: Any action flagged as potentially destructive
You can approve or deny each request individually.
CoWork OS includes configurable guardrails in Settings > Guardrails to limit what the agent can do:
| Guardrail | Description | Default |
|---|---|---|
| Token Budget | Max tokens (input + output) per task | 100,000 (enabled) |
| Cost Budget | Max estimated cost (USD) per task | $1.00 (disabled) |
| Iteration Limit | Max LLM calls per task | 50 (enabled) |
| Dangerous Commands | Block shell commands matching patterns | Enabled |
| File Size Limit | Max file size the agent can write | 50 MB (enabled) |
| Domain Allowlist | Restrict browser to approved domains | Disabled |
The following command patterns are blocked by default:
| Pattern | Risk |
|---|---|
sudo |
Elevated privileges |
rm -rf / or rm -rf ~ |
Mass deletion |
mkfs |
Filesystem formatting |
dd if= |
Direct disk writes |
| Fork bombs | Process exhaustion |
curl|bash, wget|sh |
Remote code execution |
chmod 777 |
Overly permissive |
> /dev/sd |
Direct device writes |
| `:(){ : | :& };:` |
Commands are blocked before reaching the approval dialog. You can add custom patterns in Settings.
When enabled, browser automation is restricted to specified domains:
- Exact match:
github.com - Wildcard:
*.google.com(matches subdomains) - If enabled with no domains: all navigation blocked
This prevents unintended browsing during automation tasks.
| Scope | Access Level |
|---|---|
| Workspace directories | Read/Write (based on permissions) |
| Outside workspace | No access - path traversal is blocked |
| System files | No access |
Technical details:
- Path traversal protection prevents accessing files outside the workspace
- Symlink attacks are mitigated through path normalization
- Implementation:
src/electron/agent/tools/file-tools.ts
If a workspace contains a .cowork/projects/<projectId>/ACCESS.md file, built-in tools enforce per-project access based on the task's assigned agent role:
## Allowand## Denysections accept agent role IDs (one per line prefixed with-).- Use
allto match every agent role. - Deny wins over allow.
Enforcement applies to:
- File/edit/grep/search tools when the path is inside
.cowork/projects/<projectId>/... - Workspace-kit context injection (denied projects are excluded from injected context)
Important: shell commands are not subject to these per-project access rules. Keep shell permission disabled unless you explicitly need it, and review shell approvals carefully.
When you enable shell permissions:
| Aspect | Implementation |
|---|---|
| Working directory | Restricted to workspace folder |
| Environment variables | Minimal set (PATH, HOME, USER, SHELL, LANG, TERM, TMPDIR) |
| API keys | Never passed to subprocesses |
| Timeout | Maximum 5 minutes |
| Output limit | 100KB (truncated if exceeded) |
Security note: Your API keys and secrets are never exposed to shell commands. The app creates a minimal, safe environment for each command.
The app includes Playwright for web automation:
| Capability | Details |
|---|---|
| Navigate to URLs | Any URL (user-controlled tasks) |
| Fill forms | As directed by task |
| Take screenshots | Saved to workspace |
| Execute JavaScript | Within page context only |
| Mode | Headless by default |
User agent: CoWork OS Browser Automation
The app connects to these services based on your configuration:
| Provider | Endpoint | When Used |
|---|---|---|
| Anthropic | api.anthropic.com |
Claude models |
| AWS Bedrock | bedrock-runtime.*.amazonaws.com |
Bedrock models |
| Google AI | generativelanguage.googleapis.com |
Gemini models |
| OpenRouter | openrouter.ai |
OpenRouter models |
| Ollama | localhost:11434 (default) |
Local models |
| Provider | Endpoint | When Used |
|---|---|---|
| DuckDuckGo | html.duckduckgo.com |
Free built-in web search (no API key) |
| Tavily | api.tavily.com |
Web search (API key required) |
| Brave Search | api.search.brave.com |
Web search (API key required) |
| SerpAPI | serpapi.com |
Web search (API key required) |
| Google Custom Search | customsearch.googleapis.com |
Web search (API key required) |
| Destination | Purpose |
|---|---|
api.github.com |
Update checks |
api.telegram.org |
Telegram bot (if configured) |
| Discord API | Discord bot (if configured) |
| Signal (via signal-cli) | Signal bot (if configured, local process) |
CoWork OS does not:
- Send usage analytics
- Track user behavior
- Phone home to any server
- Share your data with third parties
Your data stays on your machine and only goes to the LLM provider you explicitly configure.
All settings are now stored encrypted in the database using the SecureSettingsRepository:
| Data | Location | Encryption |
|---|---|---|
| All Settings | app.getPath('userData')/cowork-os.db |
OS Keychain + AES-256 |
| Database | app.getPath('userData')/cowork-os.db |
Settings encrypted per-category |
| Machine ID | app.getPath('userData')/.cowork-machine-id |
Stable identifier for encryption |
Typical userData locations:
- macOS:
~/Library/Application Support/cowork-os/ - Linux:
~/.config/cowork-os/ - Windows:
%APPDATA%\\cowork-os\\
Primary: OS Keychain (when available)
- macOS: Keychain Services
- Windows: DPAPI (Data Protection API)
- Linux: libsecret
Fallback: App-Level Encryption
- AES-256-GCM encryption
- Key derived via PBKDF2 (100,000 iterations, SHA-512)
- Stable machine ID prevents key changes on hostname updates
All these are stored encrypted in the database:
| Category | Contents |
|---|---|
voice |
Voice settings, TTS/STT API keys |
llm |
LLM provider settings, API keys |
search |
Search provider settings, API keys |
appearance |
Theme, accent color preferences |
personality |
Agent personality settings |
guardrails |
Safety limits and blocked patterns |
hooks |
Automation hooks configuration |
mcp |
MCP server configurations |
controlplane |
Control plane settings |
channels |
Channel/gateway configurations |
builtintools |
Built-in tool settings |
tailscale |
Tailscale integration settings |
queue |
Task queue settings |
tray |
Menu bar/tray settings |
Each stored setting includes:
- SHA-256 checksum for integrity verification
- Creation and update timestamps
- Automatic corruption detection on load
- Workspace configurations
- Task history, events, and logs (including task prompts and timeline messages)
- Channel/gateway configurations
- Channel message history (incoming/outgoing message content for configured channels)
- All encrypted settings (API keys, preferences, configurations)
Everything is stored locally on your machine. CoWork OS does not upload your database or message history to any CoWork OS servers.
Your API keys are:
- Encrypted using OS Keychain when available (macOS Keychain, Windows DPAPI, Linux libsecret)
- Fallback to AES-256 app-level encryption with stable machine-derived key
- Decrypted only when needed for API calls
- Never logged or displayed in full
- Never passed to shell commands or subprocesses
- Checksummed for integrity verification
| Setting | Value | Purpose |
|---|---|---|
nodeIntegration |
false |
Prevents renderer from accessing Node.js |
contextIsolation |
true |
Isolates preload scripts from page context |
sandbox |
Default | Uses Chromium sandbox |
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https:;
frame-ancestors 'none';
form-action 'self';
| Entitlement | Purpose |
|---|---|
allow-jit |
Required for V8 JavaScript engine |
allow-unsigned-executable-memory |
Required for Electron |
allow-dyld-environment-variables |
Loading native modules |
files.user-selected.read-write |
Access to user-selected folders |
network.client |
Connect to LLM APIs |
Not requested: Camera, microphone, contacts, location, or other sensitive permissions.
If you use the gateway feature to connect messaging bots (Telegram, Discord, Slack, WhatsApp, iMessage, Signal):
| Mode | Description | Recommendation |
|---|---|---|
| Open | Anyone can use the bot | Not recommended for production |
| Allowlist | Only pre-approved user IDs | Good for known users |
| Pairing | Users must enter a code from the app | Best for security |
- Use pairing mode for bots accessible to others
- Generate new pairing codes for each user
- Revoke access for users who no longer need it
- Don't share bot tokens publicly
For git clones (development):
- Checks GitHub API for new releases/commits
- User initiates update manually
- Runs:
git pull,npm run setup,npm run build - Requires app restart
For packaged builds:
- Uses electron-updater with GitHub releases
- Downloads signed releases from official repo
- Verifies integrity before installing
| Risk | Mitigation |
|---|---|
| Malicious code in update | Updates are user-initiated, not automatic |
| Compromised dependencies | Dependencies from reputable sources only |
| npm install risks | Third-party lifecycle scripts disabled via .npmrc; npm run setup handles native rebuilds explicitly |
Note: If you're security-conscious, review changes before updating:
git fetch origin
git diff HEAD..origin/main- Review shell commands before approving - read what will execute
- Use dedicated workspaces - don't point at sensitive directories
- Enable minimal permissions - only enable what you need
- Keep updated - security fixes come through updates
- Protect your API keys - don't share configuration files
- Never use "open" mode for public bots
- Use pairing codes for secure user onboarding
- Regularly audit connected users
- Revoke access when no longer needed
- For Signal: Use a dedicated phone number (registration deactivates other Signal instances)
- Review code changes before pulling updates
- Audit dependencies periodically with
npm audit - Don't commit
.envor settings files - Use separate workspaces for testing
| Threat | Protection |
|---|---|
| Path traversal | Path normalization and validation |
| Command injection | User approval required |
| API key leakage | Encrypted storage, minimal env |
| XSS attacks | Content Security Policy |
| Unauthorized bot access | Multiple auth modes |
| Malicious skill IDs | Input validation and sanitization |
| Binary name injection | Shell metacharacter filtering |
| Risk | User Responsibility |
|---|---|
| Approving malicious commands | Review before approving |
| Workspace selection | Don't add sensitive directories |
| Bot token security | Keep tokens private |
| Update verification | Review changes if concerned |
- Protection against malicious LLM responses (AI safety)
- Physical access to your machine
- Compromised macOS system
- Malicious code you add to workspaces
In the app, navigate to your workspace settings to review:
- Read/Write/Delete/Shell permissions
- Workspace path scope
In the Gateway settings, you can:
- View all connected users
- Revoke access for specific users
- Generate new pairing codes
The app shows a notification badge when approvals are pending. Always review:
- The exact command to be executed
- The file to be deleted
- Any other sensitive operation
If you discover a security vulnerability:
- Do NOT create a public GitHub issue
- Use GitHub Security Advisories (Security tab > Report a vulnerability)
- Include reproduction steps and impact assessment
See SECURITY.md for full details.
CoWork OS includes a comprehensive security framework inspired by formal verification techniques.
Tools are categorized by risk level for policy-based access control:
| Risk Level | Tools | Description |
|---|---|---|
| Read | read_file, list_directory, search_files |
Low risk, read-only operations |
| Write | write_file, copy_file, create_directory |
Medium risk, creates/modifies files |
| Destructive | delete_file, run_command |
High risk, always requires approval |
| System | read_clipboard, take_screenshot, open_application |
System-level access |
| Network | web_search, browser_* |
External network operations |
Security policies are evaluated across multiple layers in order:
- Global Guardrails - Blocked commands, patterns
- Workspace Permissions - Read, write, delete, shell, network flags
- Context Restrictions - Gateway context (private/group/public)
- Tool-Specific Rules - Per-tool overrides
Key invariant: Once denied by any layer, a tool cannot be re-enabled by later layers. This prevents policy bypasses.
When tasks originate from gateway bots (WhatsApp/Telegram/Discord/Slack/iMessage/Signal), tools are restricted based on context:
| Context | Restrictions |
|---|---|
| Private | Full access (with approvals) |
| Group | Memory tools blocked (clipboard), destructive tools blocked |
| Public | System tools blocked, all destructive operations blocked |
This prevents accidental exposure of sensitive data in shared contexts.
Critical operations use mutex locks and idempotency guarantees to prevent race conditions:
| Operation | Protection |
|---|---|
| Pairing code verification | Mutex per channel + idempotency check |
| Approval responses | Idempotency prevents double-approval |
| Task creation | Deduplication via idempotency keys |
Pairing code verification includes protection against brute-force attacks:
| Feature | Value | Description |
|---|---|---|
| Max attempts | 5 | Failed attempts before lockout |
| Lockout duration | 15 minutes | Time before retry allowed |
| Code charset | 32 characters | Excludes ambiguous chars (I, O, 1, 0) |
| Code length | 6 characters | ~1 billion combinations |
| Estimated crack time | >1000 years | With lockout enabled |
When a user exceeds the maximum attempts:
- Account is locked for 15 minutes
- User sees remaining lockout time
- Attempts counter resets after lockout expires
Implementation: src/electron/gateway/security.ts
On macOS, shell commands execute within a sandbox-exec profile that:
- Restricts filesystem access to workspace + temp directories
- Blocks network access unless workspace has
networkpermission - Limits write access based on workspace permissions
- Uses minimal, safe environment variables
Implementation: src/electron/agent/sandbox/runner.ts
SkillHub includes multiple security measures to prevent attacks via malicious skills:
| Protection | Description |
|---|---|
| Skill ID Validation | IDs must match ^[a-z0-9_-]+$ pattern (lowercase alphanumeric, hyphens, underscores) |
| Path Traversal Prevention | IDs containing .., /, or \ are rejected |
| Binary Name Sanitization | Binary names in requires.bins must match ^[a-zA-Z0-9._-]+$ |
| Command Injection Prevention | Shell metacharacters in binary names are blocked before which execution |
| Debounced Reloading | Rapid skill reloads are debounced (100ms) to prevent race conditions |
Rejected inputs (skill IDs):
../../../etc/passwd- Path traversalfoo/bar- Contains path separatorskill;rm -rf /- Special characters
Rejected inputs (binary names):
node; rm -rf /- Shell metacharacters$(whoami)- Command substitution`whoami`- Backtick execution
Implementation:
src/electron/agent/skill-registry.ts(skill ID validation)src/electron/agent/skill-eligibility.ts(binary name sanitization)
npm test # Run all 132 security tests
npm run test:coverage # With coverage reportTest files:
tests/security/tool-groups.test.ts- Tool categorization teststests/security/policy-manager.test.ts- Policy evaluation teststests/security/concurrency.test.ts- Mutex and idempotency teststests/security/sandbox-runner.test.ts- Sandbox execution teststests/security/gateway-security.test.ts- Brute-force protection tests
CoWork OS is designed with security in mind:
| Aspect | Status |
|---|---|
| API key storage | Encrypted (OS keychain) |
| File access | Sandboxed to workspace |
| Shell execution | Requires approval + sandbox |
| Network access | Only configured providers |
| Telemetry | None |
| Electron security | Best practices followed |
| Guardrails | Configurable limits on tokens, cost, iterations, commands, file size, and domains |
| Policy system | Monotonic deny-wins precedence |
| Gateway security | Context-aware tool isolation |
| Concurrency | Mutex locks + idempotency guarantees |
| Skill security | Input validation, path traversal protection, binary sanitization |
The security model is transparent and consent-based. You remain in control of what the AI can do on your machine.
All guardrail settings can be configured at:
- Database: Stored encrypted in
app.getPath('userData')/cowork-os.db(category:guardrails) - UI: Settings (gear icon) → Guardrails tab
Legacy JSON settings files are automatically migrated to the encrypted database:
- Migration creates a
.migration-backupfile before proceeding - On successful migration, both backup and original are deleted
- On failed migration, backup is preserved for recovery
- Migration logs are available in the app console