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.
LayerProtectionStatus
AuthenticationJWT tokens with RS256/HS256 + RBAC role enforcementActive
AuthenticationLegacy bearer token with constant-time comparison (crypto/subtle)Active
AuthenticationOAuth 2.0 + PKCE for Anthropic, OpenAI, GitHub CopilotActive
AuthorizationRole-based access control (viewer / operator / admin)Active
EncryptionAES-256-GCM encryption for stored credentialsActive
EncryptionSession data encrypted at rest with per-profile keysActive
TransportTLS 1.3 support for gRPC and REST endpointsActive
TransportmTLS support with client certificate verificationActive
KeychainOS keychain integration (macOS Keychain, Linux secret-service, Windows Credential Manager)Active
ShellPOSIX quoting to prevent shell injection in argumentsActive
EditorsEDITOR validation against allowlist of known editorsActive
Agent Commands150+ command allowlist (strict mode) or 50+ denylist patterns (permissive mode)Active
Agent PathsRead path blocking outside workspace directoryActive
Agent ShellShell config sourcing disabled by defaultActive
Agent OutputOutput sanitizer strips ANSI escape sequences and truncates large outputActive
PoliciesWord-boundary matching to prevent permission escalationActive
PluginsEd25519 signature verification for plugin binariesActive
PluginsQuarantine period for newly installed unsigned pluginsActive
PluginsPer-plugin permission manifest (network, filesystem, exec)Active
gRPCSSRF prevention with private IP blocking on outbound requestsActive
gRPCRate limiting (token bucket) per client IPActive
gRPCMaximum message size limits (send/receive)Active
gRPCMaximum concurrent stream limitsActive
gRPCInput validation on all RPC fieldsActive
gRPCReflection disabled by default (hides service schema)Active
AuditStructured JSON audit logging for all sensitive operationsActive
Binariesstty resolved via exec.LookPath (prevents PATH injection)Active
ContainersRead-only filesystem, no-new-privileges, drop ALL capabilitiesActive
KubernetesFail-closed authentication for operator webhooksActive
KubernetesResource type allowlist for operator actionsActive
KubernetesLog scrubbing of secrets and tokensActive
KubernetesCORS policy with configurable allowed originsActive
KubernetesRBAC namespace-scoped by default, restrictive SecurityContextActive
KubernetesNetworkPolicy for pod-level network segmentationActive
NetworkTLS optional with warning when disabledActive
EnvironmentEnv variable redaction in logs and error messagesActive
HistoryDisable history recording for sensitive sessionsActive
SessionConfigurable session TTL with automatic expirationActive
CI/CDgovulncheck, gosec, Dependabot, Cosign image signingActive
ErrorsAll critical-path errors (io.ReadAll, json.Marshal) handledActive
ProtoMeta field preserved in proto conversion (round-trip SessionData)Active

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.
export CHATCLI_JWT_SECRET="your-256-bit-secret-key-here"
export CHATCLI_JWT_ISSUER="chatcli-server"
export CHATCLI_JWT_AUDIENCE="chatcli-api"
chatcli server

RBAC Roles

Three built-in roles control access to API endpoints and operations:
RolePermissionsTypical Use
viewerRead-only access to incidents, SLOs, analytics, audit logsDashboards, monitoring
operatorViewer + acknowledge/resolve incidents, approve remediations, manage runbooksOn-call engineers
adminFull access including configuration, user management, destructive operationsPlatform admins
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.
chatcli server --token my-secret-token

OAuth 2.0 + PKCE

ChatCLI supports OAuth 2.0 with PKCE for the following providers:
ProviderFlowToken Storage
AnthropicAuthorization Code + PKCEAES-256-GCM encrypted file
OpenAIAuthorization Code + PKCEAES-256-GCM encrypted file
GitHub CopilotDevice Code FlowAES-256-GCM encrypted file
# Interactive OAuth login
/auth login anthropic
/auth login openai
/auth login github-copilot
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.
FilePermissionContent
~/.chatcli/auth-profiles.json0600AES-256-GCM encrypted OAuth credentials
~/.chatcli/.auth-key0600AES-256-GCM encryption key
~/.chatcli/coder_policy.json0600Coder policy rules

Session Encryption

Session data can be encrypted at rest when a custom encryption key is provided:
export CHATCLI_ENCRYPTION_KEY="your-32-byte-hex-key"

TLS 1.3 Transport Security

chatcli server --tls-cert cert.pem --tls-key key.pem
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:
# 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:
# Options: "auto" (default), "file", "keychain"
export CHATCLI_KEYCHAIN_BACKEND=keychain
BackendmacOSLinuxWindows
keychainKeychain.appsecret-service (GNOME Keyring)Credential Manager
file~/.chatcli/.auth-key~/.chatcli/.auth-key%APPDATA%\chatcli\.auth-key
autoKeychain if available, else filesecret-service if available, else fileCredential 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:
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
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
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
curl, wget, ssh, scp, rsync, ping, dig, nslookup, host,
kubectl, helm, docker, docker-compose, podman, terraform,
aws, gcloud, az, eksctl, kustomize, istioctl, argocd, flux
jq, yq, xmllint, csvtool, column, fold, fmt, expand, unexpand,
paste, join, comm, look, strings, hexdump, xxd, base64, md5sum,
sha256sum, openssl
# 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:
# 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:
CategoryExamples
Data destructionrm -rf /, dd if=, mkfs, drop database
Remote executioncurl | bash, wget | sh, base64 | bash
Code injectionpython -c, perl -e, ruby -e, node -e, php -r, eval
Command substitution$(curl ...), `wget ...`
Process substitution<(cmd), >(cmd)
Privilege escalationsudo, chmod 777 /, chown -R /
Network manipulationnc -l, iptables -F, /dev/tcp/
Kernelinsmod, modprobe, rmmod, sysctl -w
Evasion${IFS;cmd}, VAR=x; bash, export PATH=
# 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:
# 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:
# 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
# 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:
vim, vi, nvim, nano, emacs, code, subl, micro, helix, hx,
ed, pico, joe, ne, kate, gedit, kwrite, notepad++, atom
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:
# 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:
// 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.
1

Generate a signing key pair

chatcli plugin keygen --output ~/.chatcli/plugin-keys/
# Creates: plugin-signing.key (private) and plugin-signing.pub (public)
2

Sign your plugin

chatcli plugin sign \
  --binary ./my-plugin \
  --key ~/.chatcli/plugin-keys/plugin-signing.key \
  --output ./my-plugin.sig
3

Distribute with signature

my-plugin          # Plugin binary
my-plugin.sig      # Ed25519 signature
my-plugin.pub      # Public key (or register in trusted keys)
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:
# Allow unsigned plugins (NOT recommended for production)
export CHATCLI_ALLOW_UNSIGNED_PLUGINS=true
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:
{
  "name": "my-plugin",
  "version": "1.0.0",
  "permissions": {
    "network": false,
    "filesystem": {
      "read": ["/workspace"],
      "write": ["/workspace/.output"]
    },
    "exec": ["git", "go"]
  }
}
PermissionDescriptionDefault
networkAllow outbound network accessfalse
filesystem.readAllowed read pathsWorkspace only
filesystem.writeAllowed write pathsWorkspace only
execAllowed executablesNone

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)
# 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:
# 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:
# 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:
# Path for audit log file
export CHATCLI_AUDIT_LOG_PATH=/var/log/chatcli/audit.json
Example audit log entry:
{
  "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:
# 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
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.
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)
Don’t confuse the two Auth Secrets — both typically live in the operator’s namespace:
SecretPurposeConsumerField
chatcli-operator-secretsOperator REST API auth (dashboard, /api/v1/*)operator pod (this chapter)api-keys (YAML)
chatcli-api-keysLLM provider keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) used by the chatcli gatewaychatcli server pod via Instance.spec.apiKeys.nameone 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>.
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:
# 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:
# 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:
# Helm values.yaml
server:
  cors:
    allowedOrigins:
      - "https://dashboard.example.com"
    allowedMethods:
      - "GET"
      - "POST"
      - "PUT"
      - "DELETE"
    allowCredentials: true

RBAC and NetworkPolicy

# values.yaml
rbac:
  create: true
  clusterWide: false   # Role (namespace-scoped)
The Helm chart includes a NetworkPolicy that restricts pod communication:
# 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:
# 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
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:
# Enable dev mode (disables TLS requirement and strict auth)
export CHATCLI_OPERATOR_DEV_MODE=true
Never enable CHATCLI_OPERATOR_DEV_MODE in production. It disables critical security checks.

Operator TLS

# 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:
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
MeasureProtection
read_only: truePrevents malware from writing files to the container filesystem
tmpfsProvides an in-memory /tmp directory with limited size
no-new-privilegesPrevents child processes from gaining more privileges than the parent
Resource limitsPrevents excessive CPU/memory consumption (DoS)

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.
govulncheck ./...
2

gosec

Static analysis security scanner for Go code that detects common vulnerabilities.
gosec ./...
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.
# Verify a ChatCLI image
cosign verify ghcr.io/diillson/chatcli:latest \
  --certificate-identity-regexp=".*" \
  --certificate-oidc-issuer-regexp=".*"

Coder Mode Governance (Policy Manager)

Word Boundary Matching

The policy system uses word boundary matching to prevent permission escalation by prefix. Example:
RuleCommandResult
@coder read = allow@coder read file.txtAllowed
@coder read = allow@coder readlink /tmpBlocked (ask)
@coder read --file /etc = deny@coder read --file /etc/passwdBlocked (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:
{
  "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.

Security Environment Variables Reference

Complete reference of all security-related environment variables:

Server Security

VariableDescriptionDefault
CHATCLI_JWT_SECRETJWT signing secret (HS256) or path to RSA key (RS256)""
CHATCLI_JWT_ISSUERExpected JWT issuer claim""
CHATCLI_JWT_AUDIENCEExpected JWT audience claim""
CHATCLI_RATE_LIMIT_RPSRate limit: sustained requests per second10
CHATCLI_RATE_LIMIT_BURSTRate limit: burst capacity20
CHATCLI_MAX_RECV_MSG_SIZEMaximum gRPC receive message size (bytes)4194304
CHATCLI_MAX_SEND_MSG_SIZEMaximum gRPC send message size (bytes)4194304
CHATCLI_MAX_CONCURRENT_STREAMSMaximum concurrent gRPC streams per connection100
CHATCLI_BIND_ADDRESSNetwork interface to bind to. Auto-detects 0.0.0.0 in Kubernetes.127.0.0.1 / 0.0.0.0 (K8s)
CHATCLI_AUDIT_LOG_PATHPath for structured audit log file""
CHATCLI_LOG_FILEApplication log file path~/.chatcli/app.log
CHATCLI_LOG_MAX_SIZE_MBMax log file size before rotation (MB)100
CHATCLI_LOG_MAX_BACKUPSNumber of rotated log files to keep3
CHATCLI_LOG_MAX_AGE_DAYSMaximum age of rotated log files (days)30
CHATCLI_DEBUGEnable debug mode with verbose loggingfalse
CHATCLI_ALLOW_HTTP_PROVIDERSAllow HTTP (non-TLS) connections to LLM providersfalse
CHATCLI_GRPC_REFLECTIONEnable gRPC reflection (use only in dev)false
CHATCLI_SERVER_TOKENLegacy bearer token for gRPC authentication""
CHATCLI_SERVER_TLS_CERTServer TLS certificate path""
CHATCLI_SERVER_TLS_KEYServer TLS key path""

Agent Security

VariableDescriptionDefault
CHATCLI_AGENT_SECURITY_MODESecurity mode: strict (allowlist) or permissive (denylist)permissive
CHATCLI_AGENT_ALLOWLISTExtra allowed commands in strict mode (semicolon-separated)""
CHATCLI_AGENT_DENYLISTExtra denied patterns in permissive mode (semicolon-separated regex)""
CHATCLI_AGENT_WORKSPACE_STRICTRestrict file access to workspace directory onlyfalse
CHATCLI_AGENT_ALLOW_KUBECONFIGAllow agent commands to access kubeconfigfalse
CHATCLI_AGENT_EXTRA_READ_PATHSAdditional allowed read paths (semicolon-separated)""
CHATCLI_AGENT_SOURCE_SHELL_CONFIGSource shell config (~/.bashrc, etc.) in agent commandsfalse
CHATCLI_AGENT_ALLOW_SUDOAllow sudo without automatic blockingfalse
CHATCLI_AGENT_CMD_TIMEOUTTimeout per executed command10m
CHATCLI_MAX_COMMAND_OUTPUTMaximum command output size (bytes)65536

Plugin and Auth Security

VariableDescriptionDefault
CHATCLI_ALLOW_UNSIGNED_PLUGINSAllow unsigned plugins to executefalse
CHATCLI_ALLOW_INSECUREAllow insecure (non-TLS) connectionsfalse
CHATCLI_TLS_CLIENT_CERTClient TLS certificate for mTLS""
CHATCLI_TLS_CLIENT_KEYClient TLS key for mTLS""
CHATCLI_ENCRYPTION_KEYCustom encryption key for session dataAuto-generated
CHATCLI_KEYCHAIN_BACKENDKeychain backend: auto, file, keychainauto
CHATCLI_DISABLE_HISTORYDisable conversation history recordingfalse
CHATCLI_SESSION_TTLSession time-to-live before expiration24h
CHATCLI_ENV_REDACT_MODEEnv redaction: full, partial, nonefull
CHATCLI_REDACT_PATTERNSCustom redaction patterns (semicolon-separated regex)""

Operator Security

VariableDescriptionDefault
CHATCLI_OPERATOR_DEV_MODEEnable operator dev mode (relaxed security)false
CHATCLI_AIOPS_TLS_CERTAIOps REST API TLS certificate""
CHATCLI_AIOPS_TLS_KEYAIOps REST API TLS key""
CHATCLI_GRPC_TLS_CERTgRPC TLS certificate""
CHATCLI_GRPC_TLS_KEYgRPC TLS key""
CHATCLI_GRPC_TLS_CAgRPC CA certificate for mTLS verification""
CHATCLI_ALLOWED_RESOURCE_TYPESAllowed Kubernetes resource types (comma-separated)deployments,statefulsets,daemonsets
CHATCLI_LOG_SCRUB_PATTERNSPatterns 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):
export CHATCLI_DISABLE_VERSION_CHECK=true

Production Best Practices

1

Use JWT authentication with RBAC

export CHATCLI_JWT_SECRET=$(openssl rand -hex 32)
export CHATCLI_JWT_ISSUER="chatcli-production"
export CHATCLI_JWT_AUDIENCE="chatcli-api"
chatcli server
2

Enable TLS in production

chatcli server --tls-cert cert.pem --tls-key key.pem
3

Use strict agent security mode

export CHATCLI_AGENT_SECURITY_MODE=strict
export CHATCLI_AGENT_WORKSPACE_STRICT=true
4

Require plugin signatures

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

Configure rate limiting

export CHATCLI_RATE_LIMIT_RPS=10
export CHATCLI_RATE_LIMIT_BURST=20
6

Enable audit logging

export CHATCLI_AUDIT_LOG_PATH=/var/log/chatcli/audit.json
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:
resources:
  requests:
    memory: "128Mi"
    cpu: "100m"
  limits:
    memory: "512Mi"
    cpu: "500m"
10

Enable environment variable redaction

export CHATCLI_ENV_REDACT_MODE=full
11

Use OS keychain for key storage

export CHATCLI_KEYCHAIN_BACKEND=keychain
12

Keep ChatCLI updated

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

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.