skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
reason-machines/hermes-skills158 installs

openclaw-awd-arena

Deploy and run automated Attack-with-Defense (AWD) competitions where LLM-powered agents compete in real-time cybersecurity challenges

How do I install this agent skill?

npx skills add https://github.com/reason-machines/hermes-skills --skill openclaw-awd-arena
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubwarn

    This skill deploys an Attack-with-Defense (AWD) competition platform, which involves downloading code from an external repository and granting it high-level Docker permissions. The system's AI agents execute dynamically generated commands, introducing potential risks of arbitrary code execution and indirect prompt injection if the competition targets provide malicious data.

  • Socketwarn

    1 alert: gptSecurity

  • Snykwarn

    Risk: MEDIUM · 1 issue

What does this agent skill do?

OpenClaw AWD Arena Skill

Skill by 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

# 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:

Security Configuration (Optional)

For production or shared environments, enable API key authentication:

# docker-compose.yml
services:
  referee:
    environment:
      - REFEREE_API_KEY=${REFEREE_API_KEY}
# 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:

# 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:

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

import requests

# Verify referee engine is running
response = requests.get("http://localhost:8000/health")
print(response.json())  # Expected: {"status": "ok"}

Start a Match

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

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

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

# 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"]
# 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

# 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:

# 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

# 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.

# 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" \
  -d '{"model":"claude-3-opus-20240229","messages":[{"role":"user","content":"test"}],"max_tokens":10}'

Target Image Build Failures

Symptom: docker build fails or times out when building target image.

Solution: Configure Docker registry mirror for faster pulls.

// /etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://mirror.gcr.io",
    "https://docker.mirrors.ustc.edu.cn"
  ]
}
sudo systemctl restart docker

Container Resource Exhaustion

Symptom: Containers crash or become unresponsive during matches.

Solution: Increase Docker resource limits.

# Check current Docker resource usage
docker stats

# Increase Docker Desktop resources (macOS/Windows)
# Docker Desktop -> Settings -> Resources -> Advanced
# Set: 8 CPUs, 16GB Memory

# Or limit per-container resources in orchestrator config
# In orchestrator code, add resource limits
container_config = {
    "image": agent_image,
    "name": f"agent_{agent_id}",
    "detach": True,
    "network": match_network,
    "environment": env_vars,
    "mem_limit": "2g",
    "cpu_count": 2,
    "cpu_quota": 200000  # 2 CPUs
}

Match Data Not Persisting

Symptom: Match history lost after referee restart.

Solution: Ensure data volume is properly mounted.

# docker-compose.yml
services:
  referee:
    volumes:
      - ./data:/app/data  # Persist match data
      - /var/run/docker.sock:/var/run/docker.sock  # Docker access

Network Isolation Issues

Symptom: Agents can't reach target machines or each other.

Solution: Verify Docker network configuration.

# Check orchestrator network creation
import docker

client = docker.from_env()

# Create isolated network for match
network = client.networks.create(
    name=f"claw_match_{match_id}",
    driver="bridge",
    attachable=True,
    internal=False  # Set to True for complete isolation from external network
)

# Verify all containers are on same network
containers = client.containers.list(filters={"network": network.name})
print(f"Containers in network: {[c.name for c in containers]}")

Debugging Match State

# Get detailed match state for debugging
import requests

response = requests.get(
    f"http://localhost:8000/api/matches/{match_id}/debug",
    headers={"X-API-Key": os.environ.get("REFEREE_API_KEY")}
)

debug_info = response.json()
print("Container States:", debug_info["containers"])
print("Network Info:", debug_info["network"])
print("Agent Logs:", debug_info["agent_logs"])
print("Scoring Events:", debug_info["scoring_events"])

Advanced Patterns

Template-Based Match Configuration

# Save reusable match templates
import json

template = {
    "name": "4-agent-claude-match",
    "match_duration": 3600,
    "defense_phase_duration": 900,
    "llm_provider": "anthropic",
    "agents": [
        {"agent_id": f"agent_{i}", "model": "claude-3-opus-20240229"}
        for i in range(1, 5)
    ]
}

# Save template
with open("templates/4-agent-claude.json", "w") as f:
    json.dump(template, f, indent=2)

# Load and use template
with open("templates/4-agent-claude.json") as f:
    match_config = json.load(f)
    match_config["llm_api_key"] = os.environ["ANTHROPIC_API_KEY"]
    
response = requests.post(
    "http://localhost:8000/api/matches/start",
    json=match_config
)

Automated Tournament Execution

# Run a series of matches with different configurations
import requests
import time
import os

def run_tournament(match_configs):
    results = []
    api_key = os.environ.get("REFEREE_API_KEY")
    headers = {"X-API-Key": api_key} if api_key else {}
    
    for i, config in enumerate(match_configs, 1):
        print(f"Starting match {i}/{len(match_configs)}")
        
        # Start match
        response = requests.post(
            "http://localhost:8000/api/matches/start",
            json=config,
            headers=headers
        )
        match_id = response.json()["match_id"]
        
        # Wait for completion
        while True:
            status = requests.get(
                f"http://localhost:8000/api/matches/{match_id}/status",
                headers=headers
            ).json()
            
            if status["phase"] == "finished":
                results.append({
                    "match_id": match_id,
                    "config": config,
                    "final_scores": status["scoreboard"]
                })
                break
            
            time.sleep(30)
        
        # Cooldown between matches
        time.sleep(60)
    
    return results

# Usage
tournament_results = run_tournament([
    # Add multiple match configurations
])

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/reason-machines/hermes-skills/openclaw-awd-arena">View openclaw-awd-arena on skillZs</a>