Skip to main content
ChatCLI was designed with defense-in-depth security. This page documents all implemented protection measures, how to configure them, and best practices for production environments.

Protection Summary

LayerProtectionStatus
AuthenticationConstant-time token comparison (crypto/subtle)Active
ShellPOSIX quoting to prevent shell argument injectionActive
EditorsEDITOR validation against allowlist of known editorsActive
Commands50+ regex patterns for dangerous command detectionActive
PoliciesWord-boundary matching to prevent permission escalationActive
gRPCReflection disabled by default (hides service schema)Active
Binariesstty resolution via exec.LookPath (prevents PATH injection)Active
Containersread-only filesystem, no-new-privileges, drop ALL capabilitiesActive
KubernetesNamespace-scoped RBAC by default, restrictive SecurityContextActive
NetworkOptional TLS with warning when disabledActive

gRPC Server Authentication

Bearer Token with Constant-Time Comparison

The gRPC server uses Bearer token authentication in the authorization header of each request. Token comparison uses crypto/subtle.ConstantTimeCompare, which prevents timing attacks — an attacker cannot infer correct characters by measuring response time.
chatcli server --token meu-token-secreto
The /Health endpoint is always accessible without authentication to allow health checks from load balancers and orchestrators.

TLS (Optional)

TLS is fully optional. In a local development environment, you can run without TLS without issues. For production, we strongly recommend enabling TLS:
chatcli server --tls-cert cert.pem --tls-key key.pem --token meu-token

Shell Injection Protection

ShellQuote — Secure POSIX Quoting

All code paths where dynamic values are interpolated into shell commands use the utils.ShellQuote() function, which applies POSIX quoting with single quotes:
// Entrada: it's a "test" $(whoami)
// Saída:   '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

Protected Points

FileContext
cli/agent_mode.goDry-run echo of commands (simulation)
cli/cli.goSourcing shell configuration file (~/.bashrc, etc.)
cli/agent/command_executor.goSourcing shell configuration file (interactive execution)

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.

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.

Command Validation

50+ Detection Patterns

The CommandValidator analyzes each command suggested by the AI before execution, checking against more than 50 regex patterns that cover:
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=

Custom Denylist

Add your own patterns via environment variable:
# Bloquear terraform destroy e kubectl delete namespace
export CHATCLI_AGENT_DENYLIST="terraform destroy;kubectl delete namespace"

sudo Control

# Permitir sudo (use com cautela)
export CHATCLI_AGENT_ALLOW_SUDO=true

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.

gRPC Server Security

gRPC Reflection (Disabled by Default)

gRPC reflection exposes the complete 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.
# Via variável de ambiente
export CHATCLI_GRPC_REFLECTION=true
chatcli server
VariableDescriptionDefault
CHATCLI_GRPC_REFLECTIONEnables gRPC reflection (true/false)false

Security Interceptors

All requests pass through a chain of interceptors:
1

Recovery

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

Logging

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

Auth

Validates Bearer token (when configured).

Version Check

ChatCLI automatically checks whether a newer version is available on GitHub. To disable (e.g., air-gapped environments or CI/CD):
export CHATCLI_DISABLE_VERSION_CHECK=true
VariableDescriptionDefault
CHATCLI_DISABLE_VERSION_CHECKDisables automatic version check (true/false)false

Container Security (Docker)

The project’s docker-compose.yml includes the following hardening measures:
services:
  chatcli-server:
    read_only: true           # Filesystem somente-leitura
    tmpfs:
      - /tmp:size=100M        # Diretório temporário em memória
    security_opt:
      - no-new-privileges:true  # Impede escalação de privilégios
    deploy:
      resources:
        limits:
          cpus: "2.0"         # Limite de CPU
          memory: 1G          # Limite de memória

What Each Measure Does

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)

Kubernetes Security (Helm)

Pod SecurityContext

The Helm chart defines a restrictive SecurityContext by default:
# values.yaml
podSecurityContext:
  runAsNonRoot: true          # Obriga execução como usuário não-root
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000
  seccompProfile:
    type: RuntimeDefault       # Filtro de syscalls do kernel

securityContext:
  allowPrivilegeEscalation: false  # Sem escalação de privilégios
  readOnlyRootFilesystem: true     # Filesystem somente-leitura
  capabilities:
    drop:
      - ALL                        # Remove TODAS as capabilities Linux

Namespace-Scoped RBAC (Default)

By default, the chart creates Role and RoleBinding (namespace-scoped) instead of ClusterRole. This ensures ChatCLI only has access to the namespace where it is deployed.
# values.yaml
rbac:
  create: true
  clusterWide: false   # false = Role (namespace-scoped, padrão)
                       # true  = ClusterRole (cluster-wide)
To monitor deployments across multiple namespaces, enable clusterWide:
helm install chatcli deploy/helm/chatcli \
  --set rbac.clusterWide=true \
  --set watcher.enabled=true

Automatic tmpfs

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

Security Environment Variables

Summary of all security-related variables:
VariableDescriptionDefault
CHATCLI_SERVER_TOKENgRPC server authentication token"" (no auth)
CHATCLI_SERVER_TLS_CERTServer TLS certificate""
CHATCLI_SERVER_TLS_KEYServer TLS key""
CHATCLI_GRPC_REFLECTIONEnables gRPC reflectionfalse
CHATCLI_DISABLE_VERSION_CHECKDisables version checkfalse
CHATCLI_AGENT_ALLOW_SUDOAllows sudo in agent modefalse
CHATCLI_AGENT_DENYLISTAdditional regex patterns to block (; separated)""
CHATCLI_AGENT_CMD_TIMEOUTExecution timeout per command10m

Credential Encryption

OAuth credentials are stored with AES-256-GCM encryption in ~/.chatcli/auth-profiles.json. The encryption key is automatically generated and saved in ~/.chatcli/.auth-key with permission 0600 (owner-only read).
FilePermissionContent
~/.chatcli/auth-profiles.json0600Encrypted OAuth credentials
~/.chatcli/.auth-key0600AES-256-GCM key
~/.chatcli/coder_policy.json0600Coder policy rules

Best Practices for Production

1

Always use an authentication token

export CHATCLI_SERVER_TOKEN=$(openssl rand -hex 32)
chatcli server --token $CHATCLI_SERVER_TOKEN
2

Enable TLS in production

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

Keep gRPC reflection disabled

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

Use namespace-scoped RBAC

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

Review Coder policies regularly

cat ~/.chatcli/coder_policy.json
6

Configure resource limits

Always set CPU and memory limits to avoid excessive consumption:
resources:
  requests:
    memory: "128Mi"
    cpu: "100m"
  limits:
    memory: "512Mi"
    cpu: "500m"
7

Keep ChatCLI up to date

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

Next Steps