Secure Your AI Agent Server: Sandboxing, Firewalls, and Monitoring
AI agents execute arbitrary actions, consume unpredictable resources, and process untrusted input by design. This guide maps each threat to a concrete Linux control.
AI agents are not normal services. A web server handles predictable HTTP requests. An AI agent executes arbitrary tool calls, spawns subprocesses, makes outbound API requests, and consumes resources in unpredictable bursts. If a prompt injection succeeds, the agent becomes an attacker with whatever privileges you gave it.
This guide treats every AI agent as untrusted code. Each section starts with a specific threat, then maps it to a Linux control you can verify. The commands work on any VPS running Debian 12 or Ubuntu 22.04+, with any agent framework: OpenClaw, Claude Code, n8n, LangChain, CrewAI, or custom setups.
Prerequisites: A VPS with root access, basic Linux and SSH knowledge (VPS security basics covers the baseline), and at least one AI agent you want to lock down. This guide assumes you have already completed initial server hardening (SSH hardening).
What makes AI agents a different security threat?
Traditional services have a bounded set of behaviors. An Nginx process serves files and proxies requests. An AI agent's behavior depends on its input, which you do not control. Three properties make agents different from anything else you run on a server:
- They execute arbitrary actions. Tool-calling agents run shell commands, write files, and make HTTP requests based on LLM output.
- They consume unpredictable resources. A reasoning loop can spike CPU to 100% for minutes. A runaway agent can burn through API tokens in seconds.
- They process untrusted input by design. The entire point of an agent is to accept natural language and act on it.
| Threat | Attack vector | Impact | Control |
|---|---|---|---|
| Shell command execution | Prompt injection via user input or tool output | Full system compromise | User isolation, container sandbox |
| Data exfiltration | Agent sends secrets via HTTP/DNS to attacker domain | Credential theft, data breach | Egress firewall, DNS filtering |
| Resource exhaustion | Infinite reasoning loop or recursive tool calls | Server crash, other services down | cgroup CPU/memory limits |
| Credential leakage | Agent logs or memorizes API keys from environment | API key theft, lateral movement | Secrets injection, env isolation |
| Lateral movement | Compromised agent pivots to other services | Full infrastructure compromise | Network segmentation, least privilege |
How do I isolate an AI agent with a dedicated Linux user?
Create a dedicated system user for each agent with no login shell, no sudo access, and a restricted home directory. This is the simplest control with the highest impact. If an agent is compromised, the attacker inherits only that user's permissions, not root.
sudo useradd --system --create-home --shell /usr/sbin/nologin agent-worker
Lock down the home directory so other users cannot read the agent's files:
sudo chmod 750 /home/agent-worker
Check the user exists with the correct shell:
getent passwd agent-worker
Expected output:
agent-worker:x:998:998::/home/agent-worker:/usr/sbin/nologin
The shell is /usr/sbin/nologin. Nobody can SSH in as this user or open an interactive session. The agent process runs via systemd, not via login.
If your agent needs to write temporary files, create a dedicated directory:
sudo mkdir -p /home/agent-worker/tmp
sudo chown agent-worker:agent-worker /home/agent-worker/tmp
sudo chmod 700 /home/agent-worker/tmp
Check permissions:
ls -la /home/agent-worker/
What this does: Even if an attacker achieves code execution through prompt injection, they are confined to /home/agent-worker with no ability to read other users' files, escalate to root, or modify system binaries.
How do I sandbox an AI agent in a Docker container?
Running your agent inside a Docker container adds a second isolation boundary. The container has its own filesystem, process namespace, and network stack. Combined with security flags, it limits what a compromised agent can do, even with code execution.
Which Docker security flags should I use for AI agents?
Use every restriction that your agent can tolerate. Start locked down and relax only what breaks. Here is a production docker run command for an AI agent:
docker run -d \
--name ai-agent \
--user 1000:1000 \
--read-only \
--tmpfs /tmp:size=100M,noexec,nosuid \
--cap-drop ALL \
--security-opt no-new-privileges:true \
--security-opt seccomp=/etc/docker/seccomp-agent.json \
--memory 2g \
--memory-swap 2g \
--cpus 1.5 \
--pids-limit 100 \
--network agent-net \
--restart unless-stopped \
--env-file /etc/agent/env \
your-agent-image:latest
What each flag does:
| Flag | Purpose | Why it matters for agents |
|---|---|---|
--user 1000:1000 |
Run as non-root inside the container | Prevents container breakout via root exploits |
--read-only |
Root filesystem is read-only | Blocks malware installation, config tampering |
--tmpfs /tmp:size=100M,noexec,nosuid |
Writable temp with no execution | Agent can write temp files but not execute binaries from /tmp |
--cap-drop ALL |
Remove all Linux capabilities | No CAP_NET_RAW (packet sniffing), no CAP_SYS_ADMIN (mount), nothing |
--security-opt no-new-privileges:true |
Prevent privilege escalation via setuid | Blocks a compromised agent from gaining root through setuid binaries |
--pids-limit 100 |
Cap process count | Stops fork bombs from a runaway agent |
--memory 2g / --memory-swap 2g |
Hard memory ceiling, no swap | Prevents OOM killing other services |
--cpus 1.5 |
CPU limit | Agent cannot starve other services |
Verify the container is running with the correct security settings:
docker inspect ai-agent --format '{{.HostConfig.SecurityOpt}}'
Expected output:
[no-new-privileges:true seccomp=/etc/docker/seccomp-agent.json]
Check it is running as non-root:
docker exec ai-agent whoami
This should return the non-root user, not root.
Custom seccomp profile for AI agents
The default Docker seccomp profile blocks about 44 dangerous syscalls. For AI agents, you can tighten this further. Create /etc/docker/seccomp-agent.json:
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"archMap": [
{
"architecture": "SCMP_ARCH_X86_64",
"subArchitectures": ["SCMP_ARCH_X86", "SCMP_ARCH_X32"]
}
],
"syscalls": [
{
"names": [
"read", "write", "close", "fstat", "lseek", "mmap", "mprotect",
"munmap", "brk", "rt_sigaction", "rt_sigprocmask", "ioctl",
"access", "pipe", "select", "sched_yield", "mremap", "msync",
"mincore", "madvise", "dup", "dup2", "nanosleep", "getpid",
"socket", "connect", "sendto", "recvfrom", "sendmsg", "recvmsg",
"bind", "listen", "accept", "getsockname", "getpeername",
"setsockopt", "getsockopt", "clone", "execve", "exit",
"wait4", "kill", "uname", "fcntl", "flock", "fsync",
"fdatasync", "truncate", "ftruncate", "getdents", "getcwd",
"chdir", "openat", "newfstatat", "readlinkat", "fchmodat",
"set_tid_address", "exit_group", "epoll_wait", "epoll_ctl",
"tgkill", "futex", "set_robust_list", "get_robust_list",
"epoll_create1", "pipe2", "clock_gettime", "clock_nanosleep",
"prlimit64", "getrandom", "memfd_create", "statx",
"rseq", "close_range", "poll", "getuid", "getgid",
"geteuid", "getegid", "arch_prctl", "sigaltstack",
"rt_sigreturn", "accept4", "pread64", "pwrite64",
"writev", "readv", "sched_getaffinity"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
This profile allows only the syscalls needed for a typical Python/Node.js agent process. Everything else, including mount, ptrace, reboot, kexec_load, and init_module, returns a permission error.
Set proper permissions on the profile:
sudo chmod 644 /etc/docker/seccomp-agent.json
sudo chown root:root /etc/docker/seccomp-agent.json
Test that the container starts with the custom profile:
docker run --rm --security-opt seccomp=/etc/docker/seccomp-agent.json alpine echo "seccomp works"
If you see seccomp works, the profile is valid.
For deeper Docker hardening including rootless mode, see Docker security hardening. For the Docker/UFW interaction gotcha, see Docker UFW fix.
How do I block an AI agent from reaching the internet?
Threat: A compromised agent exfiltrates secrets by making outbound HTTP requests to an attacker-controlled server, or encodes data in DNS queries. Default UFW allows all outbound traffic.
Set a default-deny policy for outbound traffic, then whitelist only the endpoints your agent needs:
sudo ufw default deny outgoing
sudo ufw default deny incoming
Allow essential outbound traffic:
# DNS resolution (required for all outbound)
sudo ufw allow out 53/udp
# Allow outbound HTTPS to reach AI provider APIs
sudo ufw allow out 443/tcp
# Allow outbound HTTP for package updates only
sudo ufw allow out 80/tcp
Allow inbound SSH (so you don't lock yourself out):
sudo ufw allow in 22/tcp
Enable the firewall:
sudo ufw enable
Check the active rules:
sudo ufw status verbose
The output starts with Default: deny (incoming), deny (outgoing), followed by your allow rules.
How do I whitelist only the API endpoints my agent needs?
The rules above still allow outbound HTTPS to any destination. For tighter control, restrict outbound traffic to specific IP ranges. This requires iptables because UFW does not support destination filtering by domain.
First, resolve your AI provider's API endpoint:
dig +short api.anthropic.com
dig +short api.openai.com
Then create iptables rules for those IPs. Create /etc/iptables/agent-egress.rules:
#!/bin/bash
# Agent egress whitelist - update IPs when providers change
# Anthropic API (check current IPs with: dig +short api.anthropic.com)
ANTHROPIC_IPS="104.18.0.0/16"
# Drop all outbound from agent user except whitelisted destinations
iptables -A OUTPUT -m owner --uid-owner agent-worker -d $ANTHROPIC_IPS -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner agent-worker -d 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner agent-worker -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner agent-worker -j DROP
sudo chmod 700 /etc/iptables/agent-egress.rules
sudo bash /etc/iptables/agent-egress.rules
Verify the agent user cannot reach arbitrary hosts:
sudo -u agent-worker curl -s --max-time 5 https://example.com && echo "FAIL: egress not blocked" || echo "OK: egress blocked"
The expected output is OK: egress blocked.
DNS exfiltration note: The rules above allow DNS on port 53. A sophisticated attacker can encode data in DNS queries, sending secrets as subdomains (e.g., sk-ant-api-key.attacker.com). To close this gap, point the agent's DNS to a local resolver like unbound configured with a response policy zone (RPZ) that blocks queries to non-whitelisted domains.
Install and configure a local resolver:
sudo apt install -y unbound
Edit /etc/unbound/unbound.conf.d/agent-dns.conf:
server:
interface: 127.0.0.1
access-control: 127.0.0.0/8 allow
# Only allow resolution of specific domains
local-zone: "." deny
local-zone: "anthropic.com." transparent
local-zone: "openai.com." transparent
local-zone: "ubuntu.com." transparent
local-zone: "debian.org." transparent
sudo systemctl enable --now unbound
sudo systemctl status unbound
Then configure your agent's container or systemd service to use 127.0.0.1 as its DNS resolver instead of the system default. In Docker, add --dns 127.0.0.1 to your docker run command.
How do I rate limit AI agent API endpoints?
Threat: An exposed agent API endpoint gets hammered by bots or abused via automated prompt injection attempts. Without rate limiting, each request triggers expensive LLM API calls.
If you expose your agent through Nginx, add rate limiting at the reverse proxy layer. Add to your Nginx configuration:
http {
# 10 requests per second per IP for agent endpoints
limit_req_zone $binary_remote_addr zone=agent_api:10m rate=10r/s;
# Stricter limit for prompt submission endpoints
limit_req_zone $binary_remote_addr zone=agent_prompt:10m rate=2r/s;
server {
listen 443 ssl;
server_name agent.example.com;
location /api/agent/ {
limit_req zone=agent_api burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:8080;
}
location /api/agent/prompt {
limit_req zone=agent_prompt burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:8080;
}
}
}
Test the configuration:
sudo nginx -t && sudo systemctl reload nginx
Test rate limiting by sending rapid requests:
for i in $(seq 1 30); do curl -s -o /dev/null -w "%{http_code}\n" https://agent.example.com/api/agent/; done
The first responses return 200, then 429 once the limit kicks in.
How do I limit CPU and memory usage for an AI agent?
Threat: A reasoning loop or recursive tool call spikes CPU to 100% for minutes. Without limits, the agent starves SSH, monitoring, and other services. On a shared VPS, this can trigger provider throttling or automated suspension.
Docker resource limits
If your agent runs in Docker, the --memory and --cpus flags from the container section above handle this. Verify the limits are enforced:
docker stats ai-agent --no-stream
Check that MEM USAGE stays below MEM LIMIT and CPU % stays below your allocated cores.
Systemd cgroup limits for non-containerized agents
If your agent runs directly on the host (not in Docker), use systemd to enforce cgroup v2 limits. Create a systemd service with resource controls:
sudo systemctl edit --force --full ai-agent.service
[Unit]
Description=AI Agent Service
After=network.target
[Service]
Type=simple
User=agent-worker
Group=agent-worker
WorkingDirectory=/home/agent-worker
ExecStart=/home/agent-worker/run-agent.sh
Restart=on-failure
RestartSec=10
# Resource limits
MemoryMax=2G
MemoryHigh=1536M
CPUQuota=150%
TasksMax=100
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=tmpfs
PrivateTmp=true
ReadWritePaths=/home/agent-worker/data
# Secrets
EnvironmentFile=/etc/agent/env
[Install]
WantedBy=multi-user.target
MemoryMax=2G is a hard ceiling. The OOM killer terminates the agent if it exceeds this. MemoryHigh=1536M is a soft limit. The kernel aggressively reclaims memory above this threshold, slowing the agent before it hits the hard limit. CPUQuota=150% allows 1.5 CPU cores. TasksMax=100 prevents fork bombs.
Enable and start the service:
sudo systemctl enable --now ai-agent.service
enable makes it survive reboots. --now starts it immediately.
Verify the service is running and the limits are applied:
sudo systemctl status ai-agent.service
Check the cgroup limits:
systemctl show ai-agent.service | grep -E "(MemoryMax|CPUQuota|TasksMax)"
Expected output:
MemoryMax=2147483648
CPUQuota=150%
TasksMax=100
How do I manage secrets for AI agents without leaking them?
Threat: An agent logs its environment variables (many frameworks do this in debug mode), includes API keys in LLM context, or writes credentials to a temp file. An attacker with read access to the agent's memory or logs gets every secret.
Never put secrets in the agent's configuration file, Dockerfile, or command-line arguments. Use an environment file with restricted permissions.
Create the secrets file:
sudo mkdir -p /etc/agent
sudo touch /etc/agent/env
sudo chmod 600 /etc/agent/env
sudo chown root:root /etc/agent/env
Add your secrets:
sudo tee /etc/agent/env > /dev/null << 'EOF'
ANTHROPIC_API_KEY=sk-ant-your-key-here
AGENT_DB_PASSWORD=replace-with-generated-password
EOF
Generate strong passwords instead of making them up:
openssl rand -base64 32
The systemd service references this file with EnvironmentFile=/etc/agent/env. The agent process receives the variables but cannot read the file itself (owned by root, mode 600). Systemd reads the file and passes the variables to the process.
Verify the file permissions:
ls -la /etc/agent/env
Expected: -rw------- 1 root root. Only root can read it.
Rotation: When you rotate a secret, update /etc/agent/env and restart the service:
sudo systemctl restart ai-agent.service
The agent picks up the new values without any config file changes.
How do I monitor AI agent activity on a Linux server?
Threat: A compromised or malfunctioning agent runs silently. Without monitoring, you discover the problem when your API bill arrives or your server gets flagged for abuse.
Real-time resource monitoring
Watch resource usage live:
journalctl -u ai-agent.service -f
This streams the agent's stdout/stderr in real time. Press Ctrl+C to stop.
For Docker containers:
docker logs -f ai-agent
Monitor CPU and memory in real time:
docker stats ai-agent
What auditd rules should I set for AI agent processes?
Install auditd:
sudo apt update && sudo apt install -y auditd
Create agent-specific audit rules. Add to /etc/audit/rules.d/agent.rules:
# Monitor all commands executed by the agent user
-a exit,always -F arch=b64 -S execve -F uid=998 -k agent-exec
# Monitor file access in sensitive directories
-a exit,always -F arch=b64 -S openat -F dir=/etc -F uid=998 -k agent-etc-access
# Monitor network connections by agent user
-a exit,always -F arch=b64 -S connect -F uid=998 -k agent-network
# Monitor file permission changes by agent user
-a exit,always -F arch=b64 -S chmod,fchmod,fchmodat -F uid=998 -k agent-chmod
Replace uid=998 with your agent user's actual UID. Find it with:
id -u agent-worker
Load the new rules:
sudo augenrules --load
sudo systemctl enable --now auditd
Check the rules are loaded:
sudo auditctl -l | grep agent
The output lists all four rules.
Search for agent execution events:
sudo ausearch -k agent-exec --start recent
Automated alerting
For production, set up a simple watchdog that alerts on high resource usage. Create /usr/local/bin/agent-watchdog.sh:
#!/bin/bash
# Alert if agent container exceeds 90% memory
USAGE=$(docker stats ai-agent --no-stream --format "{{.MemPerc}}" | tr -d '%')
THRESHOLD=90
if (( $(echo "$USAGE > $THRESHOLD" | bc -l) )); then
logger -t agent-watchdog "ALERT: ai-agent memory at ${USAGE}%"
fi
sudo chmod 755 /usr/local/bin/agent-watchdog.sh
Run it every minute via cron or a systemd timer. The alerts appear in syslog, which you can forward to your monitoring stack.
How do I keep AI agent software updated safely?
Threat: Unpatched agent software contains known vulnerabilities. But updating mid-session can corrupt state or break running workflows.
For Docker-based agents, the update process is atomic:
# Pull the new image
docker pull your-agent-image:latest
# Stop the old container
docker stop ai-agent
# Remove the old container
docker rm ai-agent
# Start with the same flags (use the docker run command from above)
docker run -d \
--name ai-agent \
# ... same flags as before ...
your-agent-image:latest
For non-containerized agents:
# Check for updates to the agent
sudo systemctl stop ai-agent.service
# Update the agent (varies by framework)
# pip install --upgrade agent-framework
# npm update -g agent-tool
# Restart
sudo systemctl start ai-agent.service
# Verify it is running
sudo systemctl status ai-agent.service
Production tip: Run two agent instances behind a load balancer. Update one at a time. If the updated instance fails health checks, roll back to the previous version.
Keep the host OS patched separately:
sudo apt update && sudo apt upgrade -y
Enable automatic security updates:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Before and after: what an attacker sees
On an unhardened server where the agent runs as root with no container and no firewall:
- Full filesystem access: read
/etc/shadow, SSH keys, other users' data - Unrestricted outbound: exfiltrate data to any destination
- All syscalls available: mount filesystems, load kernel modules, sniff network traffic
- Unlimited resources: crash the server with a fork bomb or memory leak
- Persistent access: install a backdoor, add SSH keys, create new users
After applying every control in this guide:
- Confined to
/home/agent-workerwith no access to system files - Outbound HTTPS restricted to whitelisted API endpoints only
- ~80 syscalls available (down from 300+), no mount/ptrace/reboot
- Hard ceiling of 2 GB RAM and 1.5 CPU cores, 100 process limit
- Read-only filesystem, no ability to install software or persist changes
- Every command logged by auditd with searchable audit trail
The agent still works. It can call LLM APIs, process inputs, and return outputs. But a compromised agent cannot escape its box.
Something went wrong?
| Symptom | Likely cause | Fix |
|---|---|---|
| Container exits immediately | Seccomp profile too restrictive | Run with --security-opt seccomp=unconfined temporarily, check dmesg for blocked syscalls, add them to your profile |
| Agent cannot reach API | Egress firewall blocking outbound | Check sudo ufw status, verify destination IP is allowed |
| Agent killed by OOM | Memory limit too low | Increase MemoryMax or --memory, check agent's actual peak usage with docker stats |
auditd not logging |
Rules not loaded or wrong UID | Run sudo auditctl -l to verify, check UID matches agent user |
429 errors from Nginx |
Rate limit too strict | Increase burst value, check if legitimate traffic spikes are expected |
| Agent cannot write temp files | --read-only without --tmpfs |
Add --tmpfs /tmp:size=100M to your Docker run command |
Check agent logs first:
# Systemd service
journalctl -u ai-agent.service -n 50 --no-pager
# Docker container
docker logs --tail 50 ai-agent
Check audit logs for blocked actions:
sudo ausearch -k agent-exec --start today -i
FAQ
Can I run AI agents as root safely?
No. Running agents as root means any prompt injection gives the attacker full system control. There is no compensating control that makes running as root acceptable. Always use a dedicated non-root user.
Do I need Docker to secure an AI agent?
No. Linux user isolation, systemd security directives (ProtectSystem, NoNewPrivileges, PrivateTmp), and cgroup limits provide strong isolation without Docker. Docker adds a container boundary, which is valuable defense in depth. Use it if you can, but user isolation alone stops most prompt-injection-to-root-shell attacks.
How much CPU should I allocate to an AI agent?
Start with 1-2 CPU cores (CPUQuota=150% in systemd or --cpus 1.5 in Docker) and 2 GB RAM on an 8 GB VPS. Monitor actual usage with docker stats or systemctl status for a week, then adjust. Agents are bursty: they idle between requests and spike during reasoning. The limits prevent spikes from affecting other services.
How do I secure multiple agents on the same server?
Create a separate Linux user and container for each agent. Each gets its own cgroup limits, egress rules, and audit trail. Use Docker networks to isolate inter-agent traffic. Never share secrets between agents.
Copyright 2026 Virtua.Cloud. All rights reserved. This content is original work by the Virtua.Cloud team. Reproduction, republication, or redistribution without written permission is prohibited.