Security Hardening

Harden your Reviewate deployment with container isolation, network controls, and credential management.

Overview

Reviewate runs AI agents that execute code, read files, and interact with GitHub/GitLab. Because agent behavior is driven by the code being reviewed (which may contain prompt injection attempts), defense in depth matters.

This guide covers hardening options beyond the secure defaults that Reviewate ships out of the box.

What Ships by Default

Both Docker and Kubernetes backends enforce these controls automatically:

ControlDockerKubernetes
Non-root execution (UID 1000)YesYes
Read-only root filesystemYesYes
Drop all Linux capabilitiesYesVia PodSecurityPolicy/PSA
No privilege escalationYesYes
Memory and CPU limitsYesYes
PID limit (256)YesVia cluster defaults
Ephemeral containers (destroyed after review)YesYes
/tmp as tmpfs / emptyDirYesYes (1Gi)
Secret scanning (gitleaks) before postingYesYes
Short-lived platform tokensYesYes
Execution timeout (10 min)YesYes

Network Isolation

By default, review containers have unrestricted network access. This is the most important area to harden.

Why It Matters

Review containers need outbound access to:

  • api.anthropic.com (or your LLM proxy) for AI model calls
  • api.github.com / github.com for code review operations
  • gitlab.com (or your self-hosted instance) for GitLab operations

They do not need access to your database, Redis, backend API, or other internal services. Without network restrictions, a prompt-injected agent could potentially reach these.

Kubernetes: NetworkPolicy

The recommended approach for Kubernetes. Apply these to your review jobs namespace:

# Block all incoming traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: reviewate-jobs
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress: []
---
# Allow only external HTTPS (block private IPs)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-egress-only
  namespace: reviewate-jobs
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    # DNS resolution
    - to:
        - namespaceSelector: {}
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    # HTTPS to external IPs only
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
      ports:
        - protocol: TCP
          port: 443

This blocks access to all cluster-internal services while allowing the agent to reach GitHub, GitLab, and the Anthropic API.

If your LLM proxy (REVIEWATE_BASE_URL) or self-hosted GitLab runs on a private IP, add a specific egress rule for that address. Otherwise the agent won't be able to reach it.

Docker: Isolated Network

For Docker Compose, place review containers on a separate network that has no route to your internal services:

# docker-compose.override.yml
networks:
  review-network:
    driver: bridge
    internal: false  # allows internet egress

Then set network: review-network in your container plugin config. This prevents review containers from reaching Redis, Postgres, or the backend on the internal network.

For stricter control, use internal: true with an HTTP proxy that allowlists specific domains.

Credential Management

Current Approach

Review containers receive credentials as environment variables:

  • ANTHROPIC_API_KEY — LLM API access
  • GITHUB_TOKEN / GITLAB_TOKEN — Platform access (short-lived)

On Kubernetes, these are stored in ephemeral Secrets with ownerReference (auto-deleted with the Job). On Docker, they're passed directly as env vars.

Proxy Pattern (Advanced)

For stronger credential isolation, run an LLM proxy outside the container that injects the API key. The container sends requests to the proxy without credentials, and the proxy adds them before forwarding.

LiteLLM is the simplest option — it acts as an LLM gateway with credential injection and rate limiting:

# Run LiteLLM proxy (outside the review container)
litellm --model anthropic/claude-sonnet-4-20250514 --api_key $ANTHROPIC_API_KEY

# Configure Reviewate to use the proxy (no API key needed in container)
REVIEWATE_BASE_URL=http://litellm-proxy:4000

With this pattern, the review container never sees the Anthropic API key. Even if compromised, it can only make requests through the proxy.

The same approach works for platform tokens, though it requires a TLS-terminating proxy (like Envoy or mitmproxy) since gh and glab CLI tools communicate over HTTPS.

Kubernetes: ServiceAccount Lockdown

Review pods use a ServiceAccount (reviewate) that should have zero RBAC permissions. Verify this:

# Should return "no" for everything
kubectl auth can-i --list --as=system:serviceaccount:reviewate-jobs:reviewate

If your cluster has default ServiceAccount token mounting, disable it:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: reviewate
  namespace: reviewate-jobs
automountServiceAccountToken: false

Further Reading