Skip to main content
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.

Authentication and Authorization

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

RBAC Roles

Three built-in roles control access to API endpoints and operations:
The /Health endpoint is always accessible without authentication to support load balancer and orchestrator health checks.

Legacy Bearer Token

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

OAuth 2.0 + PKCE

ChatCLI supports OAuth 2.0 with PKCE for the following providers:
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.

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.

Session Encryption

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

TLS 1.3 Transport Security

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.

Environment Variable Redaction

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

OS Keychain Integration

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

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:

Custom Allowlist

Extend the allowlist with your own commands:

Denylist Patterns (Permissive Mode)

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

Read Path Blocking

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

Shell Configuration Sourcing

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

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

EDITOR Validation

When the user edits commands in agent mode, the EDITOR variable is validated against an allowlist of known editors:
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.

Kubeconfig Access Control

Control whether agent commands can access kubeconfig:

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:
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.
1

Generate a signing key pair

2

Sign your plugin

3

Distribute with signature

4

Verify on install

ChatCLI automatically verifies the signature when installing a plugin. If verification fails, the plugin is rejected.

Quarantine for Unsigned Plugins

Unsigned plugins enter a quarantine period before they can execute:
In production, always require plugin signatures. Unsigned plugins may contain malicious code that executes with the same permissions as ChatCLI.

Plugin Permission Manifest

Each plugin declares its required permissions in a manifest:

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)

Rate Limiting

Token-bucket rate limiting protects against abuse and DoS:

Message Size Limits

Prevent memory exhaustion from oversized messages:

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:
Example audit log entry:

Bind Address

Control which network interface the server listens on:
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.

Interceptor Chain

All requests pass through a chain of gRPC interceptors:
1

Recovery

Captures panics and returns a gRPC error instead of crashing the server.
2

Rate Limiting

Token-bucket rate limiter per client IP.
3

Logging

Records method, duration, and status of each request.
4

Auth

Validates JWT or bearer token (when configured).
5

RBAC

Checks role permissions for the requested operation.

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.
By default, reflection is disabled. Enable only for local debugging.

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)
Don’t confuse the two Auth Secrets — both typically live in the operator’s namespace: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>.
API keys stored in the Secret are hot-reloaded every 30s — no operator restart is needed.

Resource Type Allowlist

The operator can only manage resources from a configurable allowlist:
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:

CORS Policy

The REST API enforces a configurable CORS policy:

RBAC and NetworkPolicy

The Helm chart includes a NetworkPolicy that restricts pod communication:

Pod SecurityContext

The Helm chart defines a restrictive SecurityContext by default:
When securityContext.readOnlyRootFilesystem is true, the chart automatically mounts an emptyDir volume at /tmp (limited to 100Mi) so the application can write temporary files.

Operator Dev Mode

For local development, the operator can run in dev mode with relaxed security:
Never enable CHATCLI_OPERATOR_DEV_MODE in production. It disables critical security checks.

Operator TLS


Container Security (Docker)

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

CI/CD Security

ChatCLI’s CI/CD pipeline includes multiple security checks:
1

govulncheck

Scans Go dependencies for known vulnerabilities using the Go vulnerability database.
2

gosec

Static analysis security scanner for Go code that detects common vulnerabilities.
3

Dependabot

Automated dependency updates with security alerts for vulnerable packages. Configured via .github/dependabot.yml.
4

Cosign Image Signing

Container images are signed using Sigstore Cosign for supply chain verification.

Coder Mode Governance (Policy Manager)

Word Boundary Matching

The policy system uses word boundary matching to prevent permission escalation by prefix. Example: 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:
For more details on the governance system, see the Coder Mode documentation.

Security Environment Variables Reference

Complete reference of all security-related environment variables:

Server Security

Agent Security

Plugin and Auth Security

Operator Security


Version Check

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

Production Best Practices

1

Use JWT authentication with RBAC

2

Enable TLS in production

3

Use strict agent security mode

4

Require plugin signatures

Keep CHATCLI_ALLOW_UNSIGNED_PLUGINS as false (default). Only install plugins with valid Ed25519 signatures.
5

Configure rate limiting

6

Enable audit logging

7

Keep gRPC reflection disabled

Do not set CHATCLI_GRPC_REFLECTION=true in production. Use only for local debugging.
8

Use namespace-scoped RBAC

Keep rbac.clusterWide: false (default) unless you need to monitor multiple namespaces.
9

Set resource limits

Always define CPU and memory limits to prevent excessive consumption:
10

Enable environment variable redaction

11

Use OS keychain for key storage

12

Keep ChatCLI updated

The version check is enabled by default. If you disabled it with CHATCLI_DISABLE_VERSION_CHECK, check periodically:

Next Steps

Coder Mode Governance

Policy rules to control what the Coder can execute.

Configure the Server

Deploy and configure the gRPC server.

Deploy with Docker and Helm

Complete containerized deployment guide.

Environment Variables

Complete environment variables reference.

K8s Operator

AIOps autonomous remediation platform.

Plugin System

Extend ChatCLI with custom plugins.