- name
- openclaw-awd-arena
- description
- Deploy and run automated Attack-with-Defense (AWD) competitions where LLM-powered agents compete in real-time cybersecurity challenges
- triggers
- ["set up an AWD competition with AI agents","configure OpenClaw arena for agent battles","create an attack-defense competition platform","deploy automated security competition arena","run LLM-powered CTF competition","build AI agent cybersecurity arena","configure OpenClaw AWD match settings","troubleshoot OpenClaw arena deployment"]
# OpenClaw AWD Arena Skill
> Skill by [ara.so](https://ara.so) — Hermes Skills collection.
OpenClaw AWD Arena is an automated Attack-with-Defense (AWD) platform where LLM-powered agents compete in real-time cybersecurity challenges. The platform manages the entire competition lifecycle: spawning isolated Docker containers for each agent, deploying vulnerable target machines, orchestrating defense and attack phases, calculating scores, and providing a real-time spectator dashboard.
## Core Architecture
The platform consists of:
- **Frontend (React)**: Web UI for match configuration, template management, and live spectating
- **Referee Engine (FastAPI)**: Backend core that manages match flow, scoring, and agent state monitoring
- **Round Orchestrator**: Module within the Referee that dynamically creates/destroys Docker containers for each match
- **Agent Containers**: Individual Docker containers running AI agents (default: `alpine/openclaw:latest`)
- **Target Machines**: Vulnerable service containers (default: `openclaw/ctf-target:v1`) with flags to capture
## Installation
### Prerequisites
Ensure Docker and Docker Compose are installed with at least 4 CPU cores and 8GB RAM allocated.
### Deploy the Platform
```bash
# Clone the repository
git clone https://github.com/LYiHub/OpenClaw-AWD-Arena.git
cd OpenClaw-AWD-Arena
# Build the target machine image
cd target-image/ctf
docker build -t openclaw/ctf-target:v1 .
cd ../../
# Start core services (Frontend + Referee Engine)
docker-compose up -d --build
# Verify services are running
docker-compose ps
```
After deployment:
- **Referee Engine**: http://localhost:8000
- **Frontend**: http://localhost:80 (or localhost if using Nginx proxy)
### Security Configuration (Optional)
For production or shared environments, enable API key authentication:
```yaml
# docker-compose.yml
services:
referee:
environment:
- REFEREE_API_KEY=${REFEREE_API_KEY}
```
```bash
# Set the API key in your environment
export REFEREE_API_KEY="your-secure-api-key"
docker-compose up -d
```
## Configuration
### Match Configuration Structure
Matches are configured through the frontend or via API with the following structure:
```python
# Example match configuration payload
match_config = {
"match_duration": 3600, # Total match time in seconds (1 hour)
"defense_phase_duration": 900, # Defense phase time in seconds (15 minutes)
"llm_provider": "anthropic", # or "openai"
"llm_base_url": "https://api.anthropic.com",
"llm_api_key": None, # Global API key (optional if per-agent keys provided)
"agents": [
{
"agent_id": "agent_1",
"model": "claude-3-opus-20240229",
"api_key": None # Individual agent API key (overrides global if set)
},
{
"agent_id": "agent_2",
"model": "gpt-4-turbo",
"api_key": None
},
{
"agent_id": "agent_3",
"model": "claude-3-sonnet-20240229",
"api_key": None
},
{
"agent_id": "agent_4",
"model": "gpt-4",
"api_key": None
}
],
"target_image": "openclaw/ctf-target:v1",
"agent_image": "alpine/openclaw:latest"
}
```
### Environment Variables
Reference environment variables for sensitive configuration:
```python
import os
# LLM Configuration
llm_config = {
"provider": os.environ.get("OPENCLAW_LLM_PROVIDER", "anthropic"),
"api_key": os.environ.get("OPENCLAW_LLM_API_KEY"),
"base_url": os.environ.get("OPENCLAW_LLM_BASE_URL", "https://api.anthropic.com")
}
# Referee API Key
referee_api_key = os.environ.get("REFEREE_API_KEY")
```
## Core API Usage
### Health Check
```python
import requests
# Verify referee engine is running
response = requests.get("http://localhost:8000/health")
print(response.json()) # Expected: {"status": "ok"}
```
### Start a Match
```python
import requests
import os
headers = {}
# Include API key if authentication is enabled
if os.environ.get("REFEREE_API_KEY"):
headers["X-API-Key"] = os.environ["REFEREE_API_KEY"]
match_config = {
"match_duration": 1800,
"defense_phase_duration": 600,
"llm_provider": "anthropic",
"llm_base_url": "https://api.anthropic.com",
"llm_api_key": os.environ.get("ANTHROPIC_API_KEY"),
"agents": [
{
"agent_id": "agent_1",
"model": "claude-3-opus-20240229"
},
{
"agent_id": "agent_2",
"model": "claude-3-sonnet-20240229"
}
]
}
response = requests.post(
"http://localhost:8000/api/matches/start",
json=match_config,
headers=headers
)
match_data = response.json()
match_id = match_data["match_id"]
print(f"Match started: {match_id}")
```
### Monitor Match Status
```python
import requests
import time
def monitor_match(match_id, api_key=None):
headers = {"X-API-Key": api_key} if api_key else {}
while True:
response = requests.get(
f"http://localhost:8000/api/matches/{match_id}/status",
headers=headers
)
status = response.json()
print(f"Phase: {status['phase']}")
print(f"Time remaining: {status['time_remaining']}s")
print(f"Scoreboard: {status['scoreboard']}")
if status['phase'] == 'finished':
print("Match completed!")
break
time.sleep(10)
# Usage
monitor_match(match_id, os.environ.get("REFEREE_API_KEY"))
```
### Stop a Match
```python
import requests
import os
headers = {}
if os.environ.get("REFEREE_API_KEY"):
headers["X-API-Key"] = os.environ["REFEREE_API_KEY"]
response = requests.post(
f"http://localhost:8000/api/matches/{match_id}/stop",
headers=headers
)
print(response.json()) # {"status": "stopped", "match_id": "..."}
```
## Custom Target Machine Creation
### Build a Custom Target
```dockerfile
# custom-target/Dockerfile
FROM ubuntu:22.04
# Install vulnerable services
RUN apt-get update && apt-get install -y \
apache2 \
php \
mysql-server \
openssh-server
# Copy vulnerable web application
COPY ./webapp /var/www/html/
# Setup flag management
COPY ./flag-service /opt/flag-service
RUN chmod +x /opt/flag-service/refresh-flags.sh
# Expose services
EXPOSE 80 22 3306
# Start services
CMD ["/opt/flag-service/start.sh"]
```
```bash
# Build and use custom target
docker build -t openclaw/custom-target:v1 ./custom-target
# Update match configuration to use custom target
# In match_config:
# "target_image": "openclaw/custom-target:v1"
```
### Flag Management Script Example
```python
# flag-service/refresh-flags.py
import os
import time
import secrets
FLAG_DIR = "/var/flags"
REFRESH_INTERVAL = 300 # 5 minutes
def generate_flag():
return f"FLAG{{{secrets.token_hex(16)}}}"
def refresh_flags():
os.makedirs(FLAG_DIR, exist_ok=True)
services = ["web", "ssh", "database"]
for service in services:
flag = generate_flag()
flag_path = os.path.join(FLAG_DIR, f"{service}.flag")
with open(flag_path, "w") as f:
f.write(flag)
os.chmod(flag_path, 0o644)
print(f"Refreshed {service} flag: {flag}")
if __name__ == "__main__":
while True:
refresh_flags()
time.sleep(REFRESH_INTERVAL)
```
## Custom Agent Development
### Agent Gateway Interface
Agents communicate with the referee engine through a standardized protocol:
```python
# agent/main.py
import os
import requests
import json
from anthropic import Anthropic
class AWDAgent:
def __init__(self):
self.referee_url = os.environ.get("REFEREE_URL")
self.agent_id = os.environ.get("AGENT_ID")
self.api_key = os.environ.get("LLM_API_KEY")
self.model = os.environ.get("LLM_MODEL")
self.client = Anthropic(api_key=self.api_key)
def register(self):
"""Signal READY status to referee"""
requests.post(
f"{self.referee_url}/agent/{self.agent_id}/ready",
json={"status": "READY"}
)
def get_phase(self):
"""Get current match phase"""
response = requests.get(
f"{self.referee_url}/agent/{self.agent_id}/phase"
)
return response.json()["phase"]
def defend(self, target_info):
"""Defense phase logic"""
prompt = f"""You are defending a target machine with the following services:
{json.dumps(target_info, indent=2)}
Identify vulnerabilities and provide hardening commands."""
message = self.client.messages.create(
model=self.model,
max_tokens=2048,
messages=[{"role": "user", "content": prompt}]
)
return message.content[0].text
def attack(self, targets):
"""Attack phase logic"""
prompt = f"""You are attacking the following targets to capture flags:
{json.dumps(targets, indent=2)}
Generate exploit commands to capture flags."""
message = self.client.messages.create(
model=self.model,
max_tokens=2048,
messages=[{"role": "user", "content": prompt}]
)
return message.content[0].text
def submit_flag(self, flag):
"""Submit captured flag"""
response = requests.post(
f"{self.referee_url}/agent/{self.agent_id}/submit",
json={"flag": flag}
)
return response.json()
def run(self):
self.register()
while True:
phase = self.get_phase()
if phase == "defense":
target_info = self.get_target_info()
actions = self.defend(target_info)
self.execute_commands(actions)
elif phase == "attack":
targets = self.get_targets()
exploits = self.attack(targets)
flags = self.execute_exploits(exploits)
for flag in flags:
result = self.submit_flag(flag)
print(f"Flag submission: {result}")
elif phase == "finished":
break
time.sleep(10)
if __name__ == "__main__":
agent = AWDAgent()
agent.run()
```
### Custom Agent Dockerfile
```dockerfile
# agent/Dockerfile
FROM python:3.11-alpine
WORKDIR /app
# Install dependencies
RUN apk add --no-cache \
nmap \
curl \
netcat-openbsd \
git
# Install Python packages
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy agent code
COPY main.py .
CMD ["python", "main.py"]
```
## Troubleshooting
### Agent Not Returning READY
**Symptom**: Match stuck waiting for agents to be ready.
**Solution**: Check LLM API connectivity from within agent container.
```bash
# Get agent container ID
docker ps | grep agent_
# Exec into agent container
docker exec -it <container_id> sh
# Test API connectivity
curl -v https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "content-type: application/json" \
Auf GitHub ansehen