Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@ submit one that will be an automatic ban from the project.

Altimate Code is an AI-powered data engineering coding assistant that runs locally on your machine. It provides an agent system with access to powerful tools including shell execution, file operations, and web access.

### No Sandbox
### Permission System

Altimate Code does **not** sandbox the agent. The permission system exists as a UX feature to help users stay aware of what actions the agent is taking - it prompts for confirmation before executing commands, writing files, etc. However, it is not designed to provide security isolation.
Altimate Code includes a permission system that prompts for confirmation before the agent executes commands, writes files, or accesses resources outside your project. You can configure each tool as `"allow"`, `"ask"`, or `"deny"` — and use pattern-based rules to fine-tune behavior (e.g., allow `dbt run` but deny `rm *`).

If you need true isolation, run Altimate Code inside a Docker container or VM.
The permission system is designed to keep you informed and in control of what the agent does. It includes:

- **Per-tool and per-pattern controls** with wildcard matching
- **Per-agent permission overrides** (e.g., restrict `analyst` to read-only)
- **External directory detection** that prompts when the agent accesses files outside your project
- **Path traversal protection** that blocks attempts to escape the project directory
- **Doom loop detection** that alerts you when the agent repeats failed actions

However, the permission system operates at the application level. It does not provide OS-level sandboxing — the process runs with your user permissions. For high-security environments or when working with sensitive production systems, we recommend running Altimate Code inside a Docker container or VM for additional isolation.

### Server Mode

Server mode is opt-in only. When enabled, set `OPENCODE_SERVER_PASSWORD` to require HTTP Basic Auth. Without this, the server runs unauthenticated (with a warning). It is the end user's responsibility to secure the server - any functionality it provides is not a vulnerability.
Server mode is opt-in only. When enabled, set `OPENCODE_SERVER_PASSWORD` to require HTTP Basic Auth. Without this, the server runs unauthenticated (with a warning). It is the end user's responsibility to secure the server any functionality it provides is not a vulnerability.

### Out of Scope

| Category | Rationale |
| ------------------------------- | ----------------------------------------------------------------------- |
| **Server access when opted-in** | If you enable server mode, API access is expected behavior |
| **Sandbox escapes** | The permission system is not a sandbox (see above) |
| **LLM provider data handling** | Data sent to your configured LLM provider is governed by their policies |
| **MCP server behavior** | External MCP servers you configure are outside our trust boundary |
| **Malicious config files** | Users control their own config; modifying it is not an attack vector |
Expand Down
130 changes: 127 additions & 3 deletions docs/docs/configure/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,20 @@ For tools that accept arguments (like `bash`), use pattern matching:
{
"permission": {
"bash": {
"*": "ask",
"dbt *": "allow",
"git status": "allow",
"git diff *": "allow",
"rm *": "deny",
"DROP *": "deny",
"*": "ask"
"DROP *": "deny"
}
}
}
```

Patterns are matched in order -- first match wins. Use `*` as a wildcard.
Patterns are matched in order — **last matching rule wins**. Use `*` as a wildcard. Place your catch-all `"*"` rule first and more specific rules after it.

For example, with `"*": "ask"` first and `"rm *": "deny"` after it, all `rm` commands are denied while everything else prompts. If you put `"*": "ask"` last, it would override the deny rule.

## Per-Agent Permissions

Expand Down Expand Up @@ -104,3 +106,125 @@ Set permissions via environment variable:
export ALTIMATE_CLI_PERMISSION='{"bash":"deny","write":"deny"}'
altimate
```

## Recommended Configurations

### Data Engineering (Default — Balanced)

A good starting point for most data engineering workflows. Allows safe read operations, prompts for writes and commands:

```json
{
"permission": {
"read": "allow",
"glob": "allow",
"grep": "allow",
"list": "allow",
"edit": "ask",
"write": "ask",
"bash": {
"*": "ask",
"dbt *": "allow",
"git status": "allow",
"git diff *": "allow",
"git log *": "allow",
"ls *": "allow",
"cat *": "allow",
"rm *": "deny",
"DROP *": "deny",
"DELETE *": "deny",
"TRUNCATE *": "deny"
},
"external_directory": "ask"
}
}
```

### Strict (Production-Adjacent Work)

When working near production systems. Blocks destructive operations entirely and requires confirmation for everything else:

```json
{
"permission": {
"read": "allow",
"glob": "allow",
"grep": "allow",
"list": "allow",
"edit": "ask",
"write": "ask",
"bash": {
"*": "ask",
"dbt *": "ask",
"git status": "allow",
"rm *": "deny",
"DROP *": "deny",
"DELETE *": "deny",
"TRUNCATE *": "deny",
"ALTER *": "deny",
"git push *": "deny",
"git reset *": "deny"
},
"external_directory": "deny"
}
}
```

### Per-Agent Lockdown

Give each agent only the permissions it needs:

```json
{
"agent": {
"analyst": {
"permission": {
"write": "deny",
"edit": "deny",
"bash": {
"SELECT *": "allow",
"dbt docs *": "allow",
"*": "deny"
}
}
},
"builder": {
"permission": {
"bash": {
"*": "ask",
"dbt *": "allow",
"git *": "ask",
"DROP *": "deny"
}
}
}
}
}
```

## How Permissions Work

When the agent wants to use a tool, the permission system evaluates your rules in order:

1. **Config rules** — from `altimate-code.json`
2. **Agent-level rules** — per-agent overrides
3. **Session approvals** — patterns you've approved with "Allow always" during the current session

If a rule matches, it applies. If no rule matches, the default is `"ask"` — you'll be prompted.

When prompted, you have three choices:

| Choice | Effect |
|--------|--------|
| **Allow once** | Approves this single action |
| **Allow always** | Approves this pattern for the rest of the session |
| **Reject** | Blocks the action (optionally with feedback for the agent) |

"Allow always" approvals persist for your current session only. They reset when you restart Altimate Code.

## Tips

- **Start with `"ask"` and relax as you build confidence.** You can always approve patterns with "Allow always" during a session.
- **Use `"deny"` for truly dangerous commands** like `rm *`, `DROP *`, `git push --force *`, and `git reset --hard *`. These are blocked even if other rules would allow them.
- **Use per-agent permissions** to enforce least-privilege. An analyst doesn't need write access. A builder doesn't need `DROP`.
- **Review the prompt before approving.** The TUI shows you exactly what will run — including diffs for file edits and the full command for bash operations.
91 changes: 87 additions & 4 deletions docs/docs/security-faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ By default, destructive operations like `bash`, `write`, and `edit` require conf
{
"permission": {
"bash": {
"*": "ask",
"dbt *": "allow",
"git status": "allow",
"DROP *": "deny",
"rm *": "deny",
"*": "ask"
"rm *": "deny"
}
}
}
Expand All @@ -51,11 +51,11 @@ Yes. Use pattern-based permissions to deny destructive SQL:
{
"permission": {
"bash": {
"*": "ask",
"DROP *": "deny",
"DELETE *": "deny",
"TRUNCATE *": "deny",
"ALTER *": "deny",
"*": "ask"
"ALTER *": "deny"
}
}
}
Expand Down Expand Up @@ -198,6 +198,89 @@ For additional safety:
- Run against a **staging environment** before production
- Use the `analyst` agent with restricted permissions for ad-hoc queries

## What protections does Altimate Code have for file access?

Altimate Code includes several layers of protection to keep the agent within your project:

- **Project boundary enforcement** — File operations check that paths stay within your project directory (or git worktree for monorepos). Attempts to read or write outside the project trigger an `external_directory` permission prompt.
- **Symlink-aware path resolution** — Symlinks inside the project that point outside are detected and blocked. This prevents an agent from reading or writing outside your project through symlinks.
- **Path traversal blocking** — Paths containing `../` sequences that would escape the project are rejected with an "Access denied" error.
- **Sensitive file protection** — Writing to credential files (`.env`, `.ssh/`, `.aws/`, private keys) triggers a confirmation prompt, even inside the project. See [below](#why-am-i-being-prompted-to-edit-env-files) for details.
- **Bash command analysis** — The bash tool parses commands with tree-sitter to detect file operations (`rm`, `cp`, `mv`, etc.) targeting paths outside your project, and prompts for permission.
- **Non-git project safety** — For projects outside a git repository, the boundary is strictly the working directory (not the entire filesystem).

These protections operate at the application level. For additional isolation, you can run Altimate Code inside a Docker container or VM.

## Why am I being prompted to edit `.env` files?

Altimate Code prompts before modifying files that commonly contain credentials or security-sensitive configuration, even when they're inside your project. This includes:

| Pattern | Examples |
|---------|----------|
| **Environment files** | `.env`, `.env.local`, `.env.production`, `.env.staging` |
| **Credential files** | `credentials.json`, `service-account.json`, `.npmrc`, `.pypirc`, `.netrc`, `.pgpass` |
| **Secret key directories** | `.ssh/`, `.aws/`, `.gnupg/`, `.gcloud/`, `.kube/`, `.docker/` |
| **Private keys** | `*.pem`, `*.key`, `*.p12`, `*.pfx` |
| **Version control** | `.git/config`, `.git/hooks/*` |

When you see this prompt:

- **"Allow once"** — approves this single edit
- **"Allow always"** — approves edits to this specific file for the rest of the session (resets on restart)

If you frequently edit `.env` files and find the prompts disruptive, click "Allow always" on the first prompt for each file — you won't be asked again for that file during your session.

!!! tip
This protection does **not** block reading these files — only writing. The agent can still read your `.env` to understand configuration without prompting.

## What commands are blocked or prompted by default?

Altimate Code applies safe defaults so you don't have to configure anything for common protection:

| Command | Default | Why |
|---------|---------|-----|
| `rm -rf *`, `rm -fr *` | **Prompted** | Recursive deletion can be destructive. You'll see what's being deleted. |
| `git push --force *` | **Prompted** | Force-push can overwrite shared branch history. |
| `git reset --hard *` | **Prompted** | Discards uncommitted changes permanently. |
| `git clean -f *` | **Prompted** | Removes untracked files permanently. |
| `DROP DATABASE *` | **Blocked** | Almost never intentional in an agent context. |
| `DROP SCHEMA *` | **Blocked** | Almost never intentional in an agent context. |
| `TRUNCATE *` | **Blocked** | Irreversible data deletion. |
| All other commands | **Prompted** | You approve each command before it runs. |

**"Prompted"** means you'll see the command and can approve or reject it. **"Blocked"** means the agent cannot run it at all — you must override in config.

To override defaults, add rules in `altimate-code.json`. See [Permissions](configure/permissions.md) for the full configuration reference.

## Best practices for staying safe

1. **Review before approving.** The permission prompt shows you exactly what will happen — diffs for file edits, the full command for bash. Take a moment to read it.

2. **Work on a branch.** Let the agent work on a feature branch so you can review changes before merging. Git gives you a full safety net — this is the single most effective protection.

3. **Use per-agent permissions.** Give each agent only what it needs. The `analyst` agent doesn't need write access. See [Permissions](configure/permissions.md) for examples.

4. **Use read-only database credentials for exploration.** When using the agent for analysis or ad-hoc queries, connect with a read-only database user.

5. **Commit before large operations.** If the agent is about to make sweeping changes, commit your current state first. You can always `git stash` or revert.

6. **Block truly dangerous database operations.** The defaults block `DROP DATABASE`, `DROP SCHEMA`, and `TRUNCATE`. You can extend this:

```json
{
"permission": {
"bash": {
"*": "ask",
"DROP *": "deny",
"DELETE FROM *": "deny",
"TRUNCATE *": "deny"
}
}
}
```

7. **Use Docker for sensitive environments.** If you're working with production systems or sensitive data, running Altimate Code in a container provides OS-level isolation on top of the permission system.

## Where should I report security vulnerabilities?

**Do not open public GitHub issues for security vulnerabilities.** Instead, email **security@altimate.ai** with a description, reproduction steps, and your severity assessment. You'll receive acknowledgment within 48 hours. See the full [Security Policy](https://github.com/AltimateAI/altimate-code/blob/main/SECURITY.md) for details.
25 changes: 16 additions & 9 deletions packages/opencode/.github/meta/commit.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
fix: address new Sentry findings — regex m flag and off-by-one budget check
fix: UX evaluation — soften bash defaults, expand FAQ, remove .github from sensitive dirs

1. formatTrainingEntry regex: remove multiline `m` flag that could
match user content mid-string (memory/prompt.ts:82)
UX impact evaluation of each change:

2. Memory block budget check: change `<` to `<=` so blocks that fit
exactly into remaining budget are included (memory/prompt.ts:204)
1. **Bash defaults softened**: Changed destructive shell/git commands from
`deny` (blocked silently) to `ask` (prompted). `rm -rf ./build` and
`git push --force` after rebase are legitimate workflows — blocking them
without a prompt is poor UX. Database DDL (`DROP DATABASE`, `TRUNCATE`)
stays `deny` since it's almost never intentional in agent context.

3 prior Sentry findings already fixed in earlier commits:
- projectDir cache (Map keyed by Instance.directory)
- injectTrainingOnly header-only return (itemCount guard)
- orphaned section headers (first-entry pre-check)
2. **Removed `.github` from sensitive dirs**: Editing CI/CD workflows is a
core use case. Prompting on every workflow edit would cause severe
approval fatigue.

3. **Expanded FAQ**: Added "Why am I being prompted to edit .env files?"
with table of protected patterns and guidance on "Allow always".
Added "What commands are blocked or prompted by default?" with clear
table showing which commands prompt vs block. Reordered best practices
to lead with "work on a branch" (most effective, least friction).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Loading
Loading