> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enterprise Security

> Defense-in-depth security architecture: JWT + RBAC authentication, AES-256-GCM encryption, SSRF prevention, rate limiting, Ed25519 plugin signing, command allowlist, structured audit logging, and more.

ChatCLI is built with a **defense-in-depth** security architecture. This page documents every protection layer, how to configure them, and best practices for production environments.

***

## Security Overview

The table below summarizes all active protections across every layer of the stack.

| Layer              | Protection                                                                                 | Status |
| ------------------ | ------------------------------------------------------------------------------------------ | ------ |
| **Authentication** | JWT tokens with RS256/HS256 + RBAC role enforcement                                        | Active |
| **Authentication** | Legacy bearer token with constant-time comparison (`crypto/subtle`)                        | Active |
| **Authentication** | OAuth 2.0 + PKCE for Anthropic, OpenAI, GitHub Copilot                                     | Active |
| **Authorization**  | Role-based access control (viewer / operator / admin)                                      | Active |
| **Encryption**     | AES-256-GCM encryption for stored credentials                                              | Active |
| **Encryption**     | Session data encrypted at rest with per-profile keys                                       | Active |
| **Transport**      | TLS 1.3 support for gRPC and REST endpoints                                                | Active |
| **Transport**      | mTLS support with client certificate verification                                          | Active |
| **Keychain**       | OS keychain integration (macOS Keychain, Linux secret-service, Windows Credential Manager) | Active |
| **Shell**          | POSIX quoting to prevent shell injection in arguments                                      | Active |
| **Editors**        | EDITOR validation against allowlist of known editors                                       | Active |
| **Agent Commands** | 150+ command allowlist (strict mode) or 50+ denylist patterns (permissive mode)            | Active |
| **Agent Paths**    | Read path blocking outside workspace directory                                             | Active |
| **Agent Shell**    | Shell config sourcing disabled by default                                                  | Active |
| **Agent Output**   | Output sanitizer strips ANSI escape sequences and truncates large output                   | Active |
| **Policies**       | Word-boundary matching to prevent permission escalation                                    | Active |
| **Plugins**        | Ed25519 signature verification for plugin binaries                                         | Active |
| **Plugins**        | Quarantine period for newly installed unsigned plugins                                     | Active |
| **Plugins**        | Per-plugin permission manifest (network, filesystem, exec)                                 | Active |
| **gRPC**           | SSRF prevention with private IP blocking on outbound requests                              | Active |
| **gRPC**           | Rate limiting (token bucket) per client IP                                                 | Active |
| **gRPC**           | Maximum message size limits (send/receive)                                                 | Active |
| **gRPC**           | Maximum concurrent stream limits                                                           | Active |
| **gRPC**           | Input validation on all RPC fields                                                         | Active |
| **gRPC**           | Reflection disabled by default (hides service schema)                                      | Active |
| **Audit**          | Structured JSON audit logging for all sensitive operations                                 | Active |
| **Binaries**       | `stty` resolved via `exec.LookPath` (prevents PATH injection)                              | Active |
| **Containers**     | Read-only filesystem, no-new-privileges, drop ALL capabilities                             | Active |
| **Kubernetes**     | Fail-closed authentication for operator webhooks                                           | Active |
| **Kubernetes**     | Resource type allowlist for operator actions                                               | Active |
| **Kubernetes**     | Log scrubbing of secrets and tokens                                                        | Active |
| **Kubernetes**     | CORS policy with configurable allowed origins                                              | Active |
| **Kubernetes**     | RBAC namespace-scoped by default, restrictive SecurityContext                              | Active |
| **Kubernetes**     | NetworkPolicy for pod-level network segmentation                                           | Active |
| **Network**        | TLS optional with warning when disabled                                                    | Active |
| **Environment**    | Env variable redaction in logs and error messages                                          | Active |
| **History**        | Disable history recording for sensitive sessions                                           | Active |
| **Session**        | Configurable session TTL with automatic expiration                                         | Active |
| **CI/CD**          | govulncheck, gosec, Dependabot, Cosign image signing                                       | Active |
| **Errors**         | All critical-path errors (`io.ReadAll`, `json.Marshal`) handled                            | Active |
| **Proto**          | Meta field preserved in proto conversion (round-trip SessionData)                          | Active |

***

## Authentication and Authorization

### JWT Authentication (Recommended)

The gRPC and REST servers support JWT-based authentication with configurable issuer, audience, and secret. JWTs carry role claims that map to RBAC policies.

<Tabs>
  <Tab title="HS256 (Symmetric)">
    ```bash theme={"system"}
    export CHATCLI_JWT_SECRET="your-256-bit-secret-key-here"
    export CHATCLI_JWT_ISSUER="chatcli-server"
    export CHATCLI_JWT_AUDIENCE="chatcli-api"
    chatcli server
    ```
  </Tab>

  <Tab title="Via Helm">
    ```yaml theme={"system"}
    # values.yaml
    server:
      jwt:
        secret: "your-256-bit-secret-key-here"
        issuer: "chatcli-server"
        audience: "chatcli-api"
    ```
  </Tab>
</Tabs>

### RBAC Roles

Three built-in roles control access to API endpoints and operations:

| Role       | Permissions                                                                   | Typical Use            |
| ---------- | ----------------------------------------------------------------------------- | ---------------------- |
| `viewer`   | Read-only access to incidents, SLOs, analytics, audit logs                    | Dashboards, monitoring |
| `operator` | Viewer + acknowledge/resolve incidents, approve remediations, manage runbooks | On-call engineers      |
| `admin`    | Full access including configuration, user management, destructive operations  | Platform admins        |

<Info>The `/Health` endpoint is always accessible without authentication to support load balancer and orchestrator health checks.</Info>

### Legacy Bearer Token

For simpler deployments, the server supports static bearer token authentication with constant-time comparison (`crypto/subtle.ConstantTimeCompare`), preventing timing attacks.

<Tabs>
  <Tab title="Via flag">
    ```bash theme={"system"}
    chatcli server --token my-secret-token
    ```
  </Tab>

  <Tab title="Via environment variable">
    ```bash theme={"system"}
    export CHATCLI_SERVER_TOKEN=my-secret-token
    chatcli server
    ```
  </Tab>
</Tabs>

### OAuth 2.0 + PKCE

ChatCLI supports OAuth 2.0 with PKCE for the following providers:

| Provider       | Flow                      | Token Storage              |
| -------------- | ------------------------- | -------------------------- |
| Anthropic      | Authorization Code + PKCE | AES-256-GCM encrypted file |
| OpenAI         | Authorization Code + PKCE | AES-256-GCM encrypted file |
| GitHub Copilot | Device Code Flow          | AES-256-GCM encrypted file |

```bash theme={"system"}
# Interactive OAuth login
/auth login anthropic
/auth login openai
/auth login github-copilot
```

<Tip>OAuth tokens are automatically refreshed before expiration. The refresh flow uses a plain HTTP client (no logging transport) with the appropriate User-Agent header to avoid Cloudflare issues.</Tip>

***

## Encryption and Data Protection

### AES-256-GCM Credential Encryption

All OAuth credentials are encrypted at rest using **AES-256-GCM** in `~/.chatcli/auth-profiles.json`. The encryption key is automatically generated and stored with strict permissions.

| File                            | Permission | Content                                 |
| ------------------------------- | ---------- | --------------------------------------- |
| `~/.chatcli/auth-profiles.json` | `0600`     | AES-256-GCM encrypted OAuth credentials |
| `~/.chatcli/.auth-key`          | `0600`     | AES-256-GCM encryption key              |
| `~/.chatcli/coder_policy.json`  | `0600`     | Coder policy rules                      |

### Session Encryption

Session data can be encrypted at rest when a custom encryption key is provided:

```bash theme={"system"}
export CHATCLI_ENCRYPTION_KEY="your-32-byte-hex-key"
```

### TLS 1.3 Transport Security

<Tabs>
  <Tab title="Server TLS">
    ```bash theme={"system"}
    chatcli server --tls-cert cert.pem --tls-key key.pem
    ```
  </Tab>

  <Tab title="Mutual TLS (mTLS)">
    ```bash theme={"system"}
    export CHATCLI_TLS_CLIENT_CERT=/path/to/client-cert.pem
    export CHATCLI_TLS_CLIENT_KEY=/path/to/client-key.pem
    chatcli connect server:50051 --tls --ca-cert ca.pem
    ```
  </Tab>

  <Tab title="Development (no TLS)">
    ```bash theme={"system"}
    chatcli server  # Warning logged when client connects without TLS
    ```

    <Note>When the client connects without TLS, a warning is emitted to remind about production use. Functional behavior is unchanged.</Note>
  </Tab>
</Tabs>

<Info>If TLS certificate loading fails, the error is written to both **stderr** and the structured log, including the cert and key paths. In containers, this ensures the error is visible via `kubectl logs` even if the structured logger cannot flush before the crash.</Info>

### Environment Variable Redaction

Sensitive environment variables are automatically redacted in logs and error messages. You can control the redaction behavior:

```bash theme={"system"}
# Redaction mode: "full" (default), "partial" (show first/last 4 chars), "none"
export CHATCLI_ENV_REDACT_MODE=full

# Custom redaction patterns (regex, semicolon-separated)
export CHATCLI_REDACT_PATTERNS="INTERNAL_SECRET_.*;MY_TOKEN_.*"
```

### OS Keychain Integration

ChatCLI can store encryption keys in the OS keychain instead of the filesystem:

```bash theme={"system"}
# Options: "auto" (default), "file", "keychain"
export CHATCLI_KEYCHAIN_BACKEND=keychain
```

| Backend    | macOS                            | Linux                                  | Windows                                    |
| ---------- | -------------------------------- | -------------------------------------- | ------------------------------------------ |
| `keychain` | Keychain.app                     | secret-service (GNOME Keyring)         | Credential Manager                         |
| `file`     | `~/.chatcli/.auth-key`           | `~/.chatcli/.auth-key`                 | `%APPDATA%\chatcli\.auth-key`              |
| `auto`     | Keychain if available, else file | secret-service if available, else file | Credential Manager if available, else file |

***

## Agent Mode Security

### Command Allowlist (Strict Mode)

In **strict mode**, only commands from the allowlist can be executed. The default allowlist includes 150+ safe commands organized by category:

<AccordionGroup>
  <Accordion title="File Operations (30+ commands)">
    ```text theme={"system"}
    ls, cat, head, tail, wc, find, grep, rg, ag, awk, sed, sort,
    uniq, cut, tr, tee, diff, cmp, file, stat, readlink, realpath,
    basename, dirname, touch, mkdir, cp, mv, ln, chmod, chown
    ```
  </Accordion>

  <Accordion title="Development Tools (40+ commands)">
    ```text theme={"system"}
    git, go, make, cargo, rustc, npm, npx, yarn, pnpm, bun, node,
    python, python3, pip, pip3, poetry, ruby, gem, bundle, java,
    javac, mvn, gradle, dotnet, php, composer, swift, kotlinc,
    cmake, gcc, g++, clang, zig, deno, tsc, eslint, prettier
    ```
  </Accordion>

  <Accordion title="System Utilities (30+ commands)">
    ```text theme={"system"}
    echo, printf, date, cal, whoami, id, hostname, uname, env,
    printenv, which, type, command, test, true, false, sleep, time,
    timeout, seq, yes, tput, stty, clear, reset, tee, xargs, watch
    ```
  </Accordion>

  <Accordion title="Network and Cloud (30+ commands)">
    ```text theme={"system"}
    curl, wget, ssh, scp, rsync, ping, dig, nslookup, host,
    kubectl, helm, docker, docker-compose, podman, terraform,
    aws, gcloud, az, eksctl, kustomize, istioctl, argocd, flux
    ```
  </Accordion>

  <Accordion title="Text Processing (20+ commands)">
    ```text theme={"system"}
    jq, yq, xmllint, csvtool, column, fold, fmt, expand, unexpand,
    paste, join, comm, look, strings, hexdump, xxd, base64, md5sum,
    sha256sum, openssl
    ```
  </Accordion>
</AccordionGroup>

```bash theme={"system"}
# Enable strict mode (allowlist-only)
export CHATCLI_AGENT_SECURITY_MODE=strict

# Or use permissive mode (denylist-based, default)
export CHATCLI_AGENT_SECURITY_MODE=permissive
```

### Custom Allowlist

Extend the allowlist with your own commands:

```bash theme={"system"}
# Add custom commands (semicolon-separated)
export CHATCLI_AGENT_ALLOWLIST="mycli;internal-tool;company-deploy"
```

### Denylist Patterns (Permissive Mode)

In **permissive mode**, 50+ regex patterns detect and block dangerous commands:

| Category                 | Examples                                                       |
| ------------------------ | -------------------------------------------------------------- |
| **Data destruction**     | `rm -rf /`, `dd if=`, `mkfs`, `drop database`                  |
| **Remote execution**     | `curl \| bash`, `wget \| sh`, `base64 \| bash`                 |
| **Code injection**       | `python -c`, `perl -e`, `ruby -e`, `node -e`, `php -r`, `eval` |
| **Command substitution** | `$(curl ...)`, `` `wget ...` ``                                |
| **Process substitution** | `<(cmd)`, `>(cmd)`                                             |
| **Privilege escalation** | `sudo`, `chmod 777 /`, `chown -R /`                            |
| **Network manipulation** | `nc -l`, `iptables -F`, `/dev/tcp/`                            |
| **Kernel**               | `insmod`, `modprobe`, `rmmod`, `sysctl -w`                     |
| **Evasion**              | `${IFS;cmd}`, `VAR=x; bash`, `export PATH=`                    |

```bash theme={"system"}
# Add custom denylist patterns
export CHATCLI_AGENT_DENYLIST="terraform destroy;kubectl delete namespace"

# Allow sudo (use with caution)
export CHATCLI_AGENT_ALLOW_SUDO=true
```

### Read Path Blocking

In strict workspace mode, the agent can only read files within the current workspace directory:

```bash theme={"system"}
# Enable strict workspace confinement
export CHATCLI_AGENT_WORKSPACE_STRICT=true

# Add extra allowed read paths (semicolon-separated)
export CHATCLI_AGENT_EXTRA_READ_PATHS="/etc/hosts;/usr/local/share/config"
```

### Shell Configuration Sourcing

By default, shell configuration files (`~/.bashrc`, `~/.zshrc`) are **not** sourced during agent command execution to prevent malicious aliases and functions:

```bash theme={"system"}
# Enable shell config sourcing (only if you trust your shell config)
export CHATCLI_AGENT_SOURCE_SHELL_CONFIG=true
```

### Input guard — typeahead protection in security prompts

When a security box appears (coder/agent mode), three layers defend against accidental typing being consumed as a y/n response:

1. **Flush kernel TTY** — `TCIFLUSH` (Linux) / `TIOCFLUSH` (BSD/Darwin) / `FlushConsoleInputBuffer` (Windows) discards bytes in the kernel queue **before** the box renders.
2. **Drain channel** — empties the centralized non-blocking stdin channel (the 10-line buffer the reader goroutine uses).
3. **Intent debounce** — discards any input that arrives in the first **250ms** after the box is drawn (minimum human reaction window).

Without these layers, accidentally typing during the LLM stream would let the security box consume the queued bytes as approval. The first time this happened motivated the input guard.

Additionally, at the start of every agent turn, ChatCLI runs `stty sane` on the controlling `/dev/tty` to recover from a prior go-prompt teardown that may have left the terminal in raw mode (echo off). Without this reset, you type and don't see characters on screen — even though the kernel is capturing them.

### Output Sanitizer

Agent command output is sanitized before being sent to the LLM:

* ANSI escape sequences are stripped
* Output is truncated to prevent context overflow

```bash theme={"system"}
# Maximum command output size (bytes)
export CHATCLI_MAX_COMMAND_OUTPUT=65536
```

### EDITOR Validation

When the user edits commands in agent mode, the `EDITOR` variable is validated against an **allowlist of known editors**:

```text theme={"system"}
vim, vi, nvim, nano, emacs, code, subl, micro, helix, hx,
ed, pico, joe, ne, kate, gedit, kwrite, notepad++, atom
```

<Warning>If `EDITOR` contains an unknown value (e.g., `EDITOR="/tmp/exploit.sh"`), the operation is refused with an error. The validated editor is then resolved via `exec.LookPath` to obtain the absolute path.</Warning>

### Kubeconfig Access Control

Control whether agent commands can access kubeconfig:

```bash theme={"system"}
# Allow kubeconfig access in agent mode (default: false)
export CHATCLI_AGENT_ALLOW_KUBECONFIG=true
```

### Shell Injection Protection

All code paths where dynamic values are interpolated into shell commands use the `utils.ShellQuote()` function, which applies POSIX quoting with single quotes:

```go theme={"system"}
// Input:  it's a "test" $(whoami)
// Output: 'it'\''s a "test" $(whoami)'
```

This protects against:

* **Quote injection**: `'; rm -rf /; echo '`
* **Command substitution**: `$(malicious)` or `` `malicious` ``
* **Variable expansion**: `$HOME`, `${PATH}`
* **Pipe/redirection**: `| cat /etc/passwd`, `> /etc/crontab`

### Binary Resolution via LookPath

The `stty` binary (used to restore the terminal) is resolved **once** at startup via `exec.LookPath("stty")`, returning the absolute path. This prevents an attacker from placing a malicious `stty` in the PATH.

***

## Plugin Security

### Ed25519 Signature Verification

ChatCLI plugins are verified using **Ed25519 digital signatures**. Each plugin binary must be signed with the developer's private key, and the corresponding public key must be registered.

<Steps>
  <Step title="Generate a signing key pair">
    ```bash theme={"system"}
    chatcli plugin keygen --output ~/.chatcli/plugin-keys/
    # Creates: plugin-signing.key (private) and plugin-signing.pub (public)
    ```
  </Step>

  <Step title="Sign your plugin">
    ```bash theme={"system"}
    chatcli plugin sign \
      --binary ./my-plugin \
      --key ~/.chatcli/plugin-keys/plugin-signing.key \
      --output ./my-plugin.sig
    ```
  </Step>

  <Step title="Distribute with signature">
    ```text theme={"system"}
    my-plugin          # Plugin binary
    my-plugin.sig      # Ed25519 signature
    my-plugin.pub      # Public key (or register in trusted keys)
    ```
  </Step>

  <Step title="Verify on install">
    ChatCLI automatically verifies the signature when installing a plugin.
    If verification fails, the plugin is rejected.
  </Step>
</Steps>

### Quarantine for Unsigned Plugins

Unsigned plugins enter a quarantine period before they can execute:

```bash theme={"system"}
# Allow unsigned plugins (NOT recommended for production)
export CHATCLI_ALLOW_UNSIGNED_PLUGINS=true
```

<Warning>In production, always require plugin signatures. Unsigned plugins may contain malicious code that executes with the same permissions as ChatCLI.</Warning>

### Plugin Permission Manifest

Each plugin declares its required permissions in a manifest:

```json theme={"system"}
{
  "name": "my-plugin",
  "version": "1.0.0",
  "permissions": {
    "network": false,
    "filesystem": {
      "read": ["/workspace"],
      "write": ["/workspace/.output"]
    },
    "exec": ["git", "go"]
  }
}
```

| Permission         | Description                   | Default        |
| ------------------ | ----------------------------- | -------------- |
| `network`          | Allow outbound network access | `false`        |
| `filesystem.read`  | Allowed read paths            | Workspace only |
| `filesystem.write` | Allowed write paths           | Workspace only |
| `exec`             | Allowed executables           | None           |

***

## gRPC Server Security

### SSRF Prevention

The server blocks outbound requests to private IP ranges, preventing Server-Side Request Forgery attacks:

* `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` (RFC 1918)
* `127.0.0.0/8` (loopback)
* `169.254.0.0/16` (link-local, including cloud metadata endpoints)
* `::1/128`, `fc00::/7` (IPv6 private)

```bash theme={"system"}
# Allow HTTP providers (disable SSRF check for trusted internal networks)
export CHATCLI_ALLOW_HTTP_PROVIDERS=true
```

### Rate Limiting

Token-bucket rate limiting protects against abuse and DoS:

```bash theme={"system"}
# Requests per second (sustained rate)
export CHATCLI_RATE_LIMIT_RPS=10

# Burst capacity (peak requests)
export CHATCLI_RATE_LIMIT_BURST=20
```

### Message Size Limits

Prevent memory exhaustion from oversized messages:

```bash theme={"system"}
# Maximum receive message size (bytes, default: 4MB)
export CHATCLI_MAX_RECV_MSG_SIZE=4194304

# Maximum send message size (bytes, default: 4MB)
export CHATCLI_MAX_SEND_MSG_SIZE=4194304

# Maximum concurrent streams per connection
export CHATCLI_MAX_CONCURRENT_STREAMS=100
```

### Input Validation

All RPC fields are validated before processing:

* String length limits on all text fields
* Enum value validation for severity, status, etc.
* Namespace and resource name format validation (Kubernetes naming rules)
* Timestamp range validation

### Audit Logging

All sensitive operations are recorded in structured JSON audit logs:

```bash theme={"system"}
# Path for audit log file
export CHATCLI_AUDIT_LOG_PATH=/var/log/chatcli/audit.json
```

Example audit log entry:

```json theme={"system"}
{
  "timestamp": "2026-04-06T10:30:00Z",
  "action": "incident.resolve",
  "actor": "user:admin@example.com",
  "role": "admin",
  "resource": "incident/INC-2024-0042",
  "result": "success",
  "ip": "10.0.1.50",
  "details": {
    "resolution": "Scaled deployment to 5 replicas"
  }
}
```

### Bind Address

Control which network interface the server listens on:

```bash theme={"system"}
# Default: listen only on localhost (secure for local/CLI use)
export CHATCLI_BIND_ADDRESS=127.0.0.1

# In Kubernetes: auto-detected via KUBERNETES_SERVICE_HOST, defaults to 0.0.0.0
# No configuration needed!

# Manually expose on all interfaces (use only with TLS + auth)
export CHATCLI_BIND_ADDRESS=0.0.0.0
```

<Tip>In Kubernetes, the bind address is automatically set to `0.0.0.0` — no manual configuration required. The server detects the environment via the `KUBERNETES_SERVICE_HOST` variable.</Tip>

### Interceptor Chain

All requests pass through a chain of gRPC interceptors:

<Steps>
  <Step title="Recovery">
    Captures panics and returns a gRPC error instead of crashing the server.
  </Step>

  <Step title="Rate Limiting">
    Token-bucket rate limiter per client IP.
  </Step>

  <Step title="Logging">
    Records method, duration, and status of each request.
  </Step>

  <Step title="Auth">
    Validates JWT or bearer token (when configured).
  </Step>

  <Step title="RBAC">
    Checks role permissions for the requested operation.
  </Step>
</Steps>

### gRPC Reflection (Disabled by Default)

gRPC reflection exposes the full service schema, allowing tools like `grpcurl` and `grpcui` to discover and call all RPCs. In production, this can facilitate reconnaissance by attackers.

<Warning>By default, reflection is disabled. Enable only for local debugging.</Warning>

```bash theme={"system"}
export CHATCLI_GRPC_REFLECTION=true
```

***

## Kubernetes Operator Security

### Fail-Closed Authentication

The operator webhook uses **fail-closed** authentication: if the authentication service is unavailable, all requests are denied. This prevents unauthorized access during outages.

API keys are hot-reloaded every 30 seconds with the following priority order:

1. **Secret** `chatcli-operator-secrets` (priority) — `api-keys` field containing a YAML list of `{key, role, description}` entries
2. **ConfigMap** `chatcli-operator-config` (fallback) — same `api-keys` field
3. Reject the request (or accept in dev-mode if `CHATCLI_OPERATOR_DEV_MODE=true`)

<Warning>
  **Don't confuse the two Auth Secrets** — both typically live in the operator's namespace:

  | Secret                     | Purpose                                                                                         | Consumer                                                | Field                                         |
  | -------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------- |
  | `chatcli-operator-secrets` | **Operator REST API auth** (dashboard, `/api/v1/*`)                                             | operator pod (this chapter)                             | `api-keys` (YAML)                             |
  | `chatcli-api-keys`         | **LLM provider keys** (OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, etc.) used by the chatcli gateway | chatcli **server** pod via `Instance.spec.apiKeys.name` | one key per provider (`OPENAI_API_KEY`, etc.) |

  `chatcli-operator-secrets` must live **in the same namespace as the operator pod** (the controller calls `Secrets(resolveNamespace()).Get(...)` — `resolveNamespace()` reads the `POD_NAMESPACE` env var, the ServiceAccount namespace file, or falls back to the default `chatcli-system`). If you ran `helm install --namespace <X>`, create the Secret in `<X>`.
</Warning>

<Tip>API keys stored in the Secret are hot-reloaded every 30s -- no operator restart is needed.</Tip>

### Resource Type Allowlist

The operator can only manage resources from a configurable allowlist:

```bash theme={"system"}
# Comma-separated allowed resource types
export CHATCLI_ALLOWED_RESOURCE_TYPES="deployments,statefulsets,daemonsets,services,configmaps"
```

Attempts to manage resources not in the allowlist are rejected and logged.

### Log Scrubbing

Secrets, tokens, and sensitive data are automatically scrubbed from operator logs:

```bash theme={"system"}
# Custom scrub patterns (regex, semicolon-separated)
export CHATCLI_LOG_SCRUB_PATTERNS="Bearer [A-Za-z0-9._-]+;password=[^&\\s]+"
```

### CORS Policy

The REST API enforces a configurable CORS policy:

```yaml theme={"system"}
# Helm values.yaml
server:
  cors:
    allowedOrigins:
      - "https://dashboard.example.com"
    allowedMethods:
      - "GET"
      - "POST"
      - "PUT"
      - "DELETE"
    allowCredentials: true
```

### RBAC and NetworkPolicy

<Tabs>
  <Tab title="Namespace-Scoped RBAC (Default)">
    ```yaml theme={"system"}
    # values.yaml
    rbac:
      create: true
      clusterWide: false   # Role (namespace-scoped)
    ```
  </Tab>

  <Tab title="Cluster-Wide RBAC">
    ```bash theme={"system"}
    helm install chatcli oci://ghcr.io/diillson/charts/chatcli \
      --set rbac.clusterWide=true \
      --set watcher.enabled=true
    ```
  </Tab>
</Tabs>

The Helm chart includes a NetworkPolicy that restricts pod communication:

```yaml theme={"system"}
# Automatically applied when networkPolicy.enabled=true
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: chatcli-network-policy
spec:
  podSelector:
    matchLabels:
      app: chatcli
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: chatcli-client
      ports:
        - port: 50051  # gRPC
        - port: 8090   # REST API
        - port: 9090   # Metrics
  egress:
    - to:
        - namespaceSelector: {}
      ports:
        - port: 443    # LLM API calls
        - port: 6443   # Kubernetes API
```

### Pod SecurityContext

The Helm chart defines a restrictive SecurityContext by default:

```yaml theme={"system"}
# values.yaml
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000
  seccompProfile:
    type: RuntimeDefault       # Kernel syscall filter

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL
```

<Info>When `securityContext.readOnlyRootFilesystem` is `true`, the chart automatically mounts an `emptyDir` volume at `/tmp` (limited to 100Mi) so the application can write temporary files.</Info>

### Operator Dev Mode

For local development, the operator can run in dev mode with relaxed security:

```bash theme={"system"}
# Enable dev mode (disables TLS requirement and strict auth)
export CHATCLI_OPERATOR_DEV_MODE=true
```

<Warning>Never enable `CHATCLI_OPERATOR_DEV_MODE` in production. It disables critical security checks.</Warning>

### Operator TLS

```bash theme={"system"}
# AIOps REST API TLS
export CHATCLI_AIOPS_TLS_CERT=/path/to/cert.pem
export CHATCLI_AIOPS_TLS_KEY=/path/to/key.pem

# gRPC TLS with CA for mTLS
export CHATCLI_GRPC_TLS_CERT=/path/to/cert.pem
export CHATCLI_GRPC_TLS_KEY=/path/to/key.pem
export CHATCLI_GRPC_TLS_CA=/path/to/ca.pem
```

***

## Container Security (Docker)

The `docker-compose.yml` includes the following hardening measures:

```yaml theme={"system"}
services:
  chatcli-server:
    read_only: true             # Read-only filesystem
    tmpfs:
      - /tmp:size=100M          # In-memory temporary directory
    security_opt:
      - no-new-privileges:true  # Prevents privilege escalation
    deploy:
      resources:
        limits:
          cpus: "2.0"           # CPU limit
          memory: 1G            # Memory limit
```

| Measure             | Protection                                                            |
| ------------------- | --------------------------------------------------------------------- |
| `read_only: true`   | Prevents malware from writing files to the container filesystem       |
| `tmpfs`             | Provides an in-memory `/tmp` directory with limited size              |
| `no-new-privileges` | Prevents child processes from gaining more privileges than the parent |
| Resource limits     | Prevents excessive CPU/memory consumption (DoS)                       |

***

## CI/CD Security

ChatCLI's CI/CD pipeline includes multiple security checks:

<Steps>
  <Step title="govulncheck">
    Scans Go dependencies for known vulnerabilities using the Go vulnerability database.

    ```bash theme={"system"}
    govulncheck ./...
    ```
  </Step>

  <Step title="gosec">
    Static analysis security scanner for Go code that detects common vulnerabilities.

    ```bash theme={"system"}
    gosec ./...
    ```
  </Step>

  <Step title="Dependabot">
    Automated dependency updates with security alerts for vulnerable packages. Configured via `.github/dependabot.yml`.
  </Step>

  <Step title="Cosign Image Signing">
    Container images are signed using [Sigstore Cosign](https://github.com/sigstore/cosign) for supply chain verification.

    ```bash theme={"system"}
    # Verify a ChatCLI image
    cosign verify ghcr.io/diillson/chatcli:latest \
      --certificate-identity-regexp=".*" \
      --certificate-oidc-issuer-regexp=".*"
    ```
  </Step>
</Steps>

***

## Coder Mode Governance (Policy Manager)

### Word Boundary Matching

The policy system uses **word boundary matching** to prevent permission escalation by prefix. Example:

| Rule                             | Command                          | Result             |
| -------------------------------- | -------------------------------- | ------------------ |
| `@coder read` = allow            | `@coder read file.txt`           | **Allowed**        |
| `@coder read` = allow            | `@coder readlink /tmp`           | **Blocked** (ask)  |
| `@coder read --file /etc` = deny | `@coder read --file /etc/passwd` | **Blocked** (deny) |

The logic checks whether the next character after the match is a separator (space, `/`, `=`, etc.) and not a word continuation (letter, digit, `-`, `_`). This ensures that `read` does not match `readlink`.

### Default Rules

Read commands are allowed by default:

```json theme={"system"}
{
  "rules": [
    { "pattern": "@coder read", "action": "allow" },
    { "pattern": "@coder tree", "action": "allow" },
    { "pattern": "@coder search", "action": "allow" },
    { "pattern": "@coder git-status", "action": "allow" },
    { "pattern": "@coder git-diff", "action": "allow" },
    { "pattern": "@coder git-log", "action": "allow" },
    { "pattern": "@coder git-changed", "action": "allow" },
    { "pattern": "@coder git-branch", "action": "allow" }
  ]
}
```

For more details on the governance system, see the [Coder Mode documentation](/features/coder-security).

***

## Security Environment Variables Reference

Complete reference of all security-related environment variables:

### Server Security

| Variable                         | Description                                                         | Default                       |
| -------------------------------- | ------------------------------------------------------------------- | ----------------------------- |
| `CHATCLI_JWT_SECRET`             | JWT signing secret (HS256) or path to RSA key (RS256)               | `""`                          |
| `CHATCLI_JWT_ISSUER`             | Expected JWT issuer claim                                           | `""`                          |
| `CHATCLI_JWT_AUDIENCE`           | Expected JWT audience claim                                         | `""`                          |
| `CHATCLI_RATE_LIMIT_RPS`         | Rate limit: sustained requests per second                           | `10`                          |
| `CHATCLI_RATE_LIMIT_BURST`       | Rate limit: burst capacity                                          | `20`                          |
| `CHATCLI_MAX_RECV_MSG_SIZE`      | Maximum gRPC receive message size (bytes)                           | `4194304`                     |
| `CHATCLI_MAX_SEND_MSG_SIZE`      | Maximum gRPC send message size (bytes)                              | `4194304`                     |
| `CHATCLI_MAX_CONCURRENT_STREAMS` | Maximum concurrent gRPC streams per connection                      | `100`                         |
| `CHATCLI_BIND_ADDRESS`           | Network interface to bind to. Auto-detects `0.0.0.0` in Kubernetes. | `127.0.0.1` / `0.0.0.0` (K8s) |
| `CHATCLI_AUDIT_LOG_PATH`         | Path for structured audit log file                                  | `""`                          |
| `CHATCLI_LOG_FILE`               | Application log file path                                           | `~/.chatcli/app.log`          |
| `CHATCLI_LOG_MAX_SIZE_MB`        | Max log file size before rotation (MB)                              | `100`                         |
| `CHATCLI_LOG_MAX_BACKUPS`        | Number of rotated log files to keep                                 | `3`                           |
| `CHATCLI_LOG_MAX_AGE_DAYS`       | Maximum age of rotated log files (days)                             | `30`                          |
| `CHATCLI_DEBUG`                  | Enable debug mode with verbose logging                              | `false`                       |
| `CHATCLI_ALLOW_HTTP_PROVIDERS`   | Allow HTTP (non-TLS) connections to LLM providers                   | `false`                       |
| `CHATCLI_GRPC_REFLECTION`        | Enable gRPC reflection (use only in dev)                            | `false`                       |
| `CHATCLI_SERVER_TOKEN`           | Legacy bearer token for gRPC authentication                         | `""`                          |
| `CHATCLI_SERVER_TLS_CERT`        | Server TLS certificate path                                         | `""`                          |
| `CHATCLI_SERVER_TLS_KEY`         | Server TLS key path                                                 | `""`                          |

### Agent Security

| Variable                            | Description                                                          | Default      |
| ----------------------------------- | -------------------------------------------------------------------- | ------------ |
| `CHATCLI_AGENT_SECURITY_MODE`       | Security mode: `strict` (allowlist) or `permissive` (denylist)       | `permissive` |
| `CHATCLI_AGENT_ALLOWLIST`           | Extra allowed commands in strict mode (semicolon-separated)          | `""`         |
| `CHATCLI_AGENT_DENYLIST`            | Extra denied patterns in permissive mode (semicolon-separated regex) | `""`         |
| `CHATCLI_AGENT_WORKSPACE_STRICT`    | Restrict file access to workspace directory only                     | `false`      |
| `CHATCLI_AGENT_ALLOW_KUBECONFIG`    | Allow agent commands to access kubeconfig                            | `false`      |
| `CHATCLI_AGENT_EXTRA_READ_PATHS`    | Additional allowed read paths (semicolon-separated)                  | `""`         |
| `CHATCLI_AGENT_SOURCE_SHELL_CONFIG` | Source shell config (`~/.bashrc`, etc.) in agent commands            | `false`      |
| `CHATCLI_AGENT_ALLOW_SUDO`          | Allow `sudo` without automatic blocking                              | `false`      |
| `CHATCLI_AGENT_CMD_TIMEOUT`         | Timeout per executed command                                         | `10m`        |
| `CHATCLI_MAX_COMMAND_OUTPUT`        | Maximum command output size (bytes)                                  | `65536`      |

### Plugin and Auth Security

| Variable                         | Description                                                                            | Default        |
| -------------------------------- | -------------------------------------------------------------------------------------- | -------------- |
| `CHATCLI_ALLOW_UNSIGNED_PLUGINS` | Allow unsigned plugins to execute                                                      | `false`        |
| `CHATCLI_ALLOW_INSECURE`         | Allow insecure (non-TLS) connections                                                   | `false`        |
| `CHATCLI_TLS_CLIENT_CERT`        | Client TLS certificate for mTLS                                                        | `""`           |
| `CHATCLI_TLS_CLIENT_KEY`         | Client TLS key for mTLS                                                                | `""`           |
| `CHATCLI_ENCRYPTION_KEY`         | Custom encryption key for session data                                                 | Auto-generated |
| `CHATCLI_KEYCHAIN_BACKEND`       | Keychain backend: `auto`, `file`, `keychain`                                           | `auto`         |
| `CHATCLI_DISABLE_HISTORY`        | Disable conversation history recording                                                 | `false`        |
| `CHATCLI_SESSION_TTL`            | Machine-session time-to-live, in days (`0` disables; user-named sessions never expire) | `90d`          |
| `CHATCLI_ENV_REDACT_MODE`        | Env redaction: `full`, `partial`, `none`                                               | `full`         |
| `CHATCLI_REDACT_PATTERNS`        | Custom redaction patterns (semicolon-separated regex)                                  | `""`           |

### Operator Security

| Variable                         | Description                                             | Default                               |
| -------------------------------- | ------------------------------------------------------- | ------------------------------------- |
| `CHATCLI_OPERATOR_DEV_MODE`      | Enable operator dev mode (relaxed security)             | `false`                               |
| `CHATCLI_AIOPS_TLS_CERT`         | AIOps REST API TLS certificate                          | `""`                                  |
| `CHATCLI_AIOPS_TLS_KEY`          | AIOps REST API TLS key                                  | `""`                                  |
| `CHATCLI_GRPC_TLS_CERT`          | gRPC TLS certificate                                    | `""`                                  |
| `CHATCLI_GRPC_TLS_KEY`           | gRPC TLS key                                            | `""`                                  |
| `CHATCLI_GRPC_TLS_CA`            | gRPC CA certificate for mTLS verification               | `""`                                  |
| `CHATCLI_ALLOWED_RESOURCE_TYPES` | Allowed Kubernetes resource types (comma-separated)     | `deployments,statefulsets,daemonsets` |
| `CHATCLI_LOG_SCRUB_PATTERNS`     | Patterns to scrub from logs (semicolon-separated regex) | Built-in patterns                     |

***

## Version Check

ChatCLI automatically checks for newer versions on GitHub. To disable (e.g., air-gapped environments or CI/CD):

```bash theme={"system"}
export CHATCLI_DISABLE_VERSION_CHECK=true
```

***

## Production Best Practices

<Steps>
  <Step title="Use JWT authentication with RBAC">
    ```bash theme={"system"}
    export CHATCLI_JWT_SECRET=$(openssl rand -hex 32)
    export CHATCLI_JWT_ISSUER="chatcli-production"
    export CHATCLI_JWT_AUDIENCE="chatcli-api"
    chatcli server
    ```
  </Step>

  <Step title="Enable TLS in production">
    ```bash theme={"system"}
    chatcli server --tls-cert cert.pem --tls-key key.pem
    ```
  </Step>

  <Step title="Use strict agent security mode">
    ```bash theme={"system"}
    export CHATCLI_AGENT_SECURITY_MODE=strict
    export CHATCLI_AGENT_WORKSPACE_STRICT=true
    ```
  </Step>

  <Step title="Require plugin signatures">
    Keep `CHATCLI_ALLOW_UNSIGNED_PLUGINS` as `false` (default). Only install plugins with valid Ed25519 signatures.
  </Step>

  <Step title="Configure rate limiting">
    ```bash theme={"system"}
    export CHATCLI_RATE_LIMIT_RPS=10
    export CHATCLI_RATE_LIMIT_BURST=20
    ```
  </Step>

  <Step title="Enable audit logging">
    ```bash theme={"system"}
    export CHATCLI_AUDIT_LOG_PATH=/var/log/chatcli/audit.json
    ```
  </Step>

  <Step title="Keep gRPC reflection disabled">
    Do not set `CHATCLI_GRPC_REFLECTION=true` in production. Use only for local debugging.
  </Step>

  <Step title="Use namespace-scoped RBAC">
    Keep `rbac.clusterWide: false` (default) unless you need to monitor multiple namespaces.
  </Step>

  <Step title="Set resource limits">
    Always define CPU and memory limits to prevent excessive consumption:

    ```yaml theme={"system"}
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "512Mi"
        cpu: "500m"
    ```
  </Step>

  <Step title="Enable environment variable redaction">
    ```bash theme={"system"}
    export CHATCLI_ENV_REDACT_MODE=full
    ```
  </Step>

  <Step title="Use OS keychain for key storage">
    ```bash theme={"system"}
    export CHATCLI_KEYCHAIN_BACKEND=keychain
    ```
  </Step>

  <Step title="Keep ChatCLI updated">
    The version check is enabled by default. If you disabled it with `CHATCLI_DISABLE_VERSION_CHECK`, check periodically:

    ```bash theme={"system"}
    chatcli --version
    ```
  </Step>
</Steps>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Coder Mode Governance" icon="shield-halved" href="/features/coder-security">
    Policy rules to control what the Coder can execute.
  </Card>

  <Card title="Configure the Server" icon="server" href="/features/server-mode">
    Deploy and configure the gRPC server.
  </Card>

  <Card title="Deploy with Docker and Helm" icon="docker" href="/getting-started/docker-deployment">
    Complete containerized deployment guide.
  </Card>

  <Card title="Environment Variables" icon="sliders" href="/reference/environment-variables">
    Complete environment variables reference.
  </Card>

  <Card title="K8s Operator" icon="dharmachakra" href="/features/k8s-operator">
    AIOps autonomous remediation platform.
  </Card>

  <Card title="Plugin System" icon="puzzle-piece" href="/features/plugin-system">
    Extend ChatCLI with custom plugins.
  </Card>
</CardGroup>

***
