agenthub/test/pen-test.sh
Paperclip FoundingEngineer bdd5d92ba7 Initial AgentHub codebase for Coolify deployment
Complete implementation ready for Coolify:
- Node.js 22 + Fastify + socket.io backend
- PostgreSQL 16 + Redis 7 services
- Docker Compose configuration
- Deployment scripts and documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-01 21:25:57 +00:00

174 lines
4.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# Basic penetration testing for AgentHub
# Run before each release
set -e
BASE_URL="${TEST_URL:-http://localhost:3000}"
PASS=0
FAIL=0
echo "=== AgentHub Pen-Test Suite ==="
echo "Target: $BASE_URL"
echo ""
# Helper functions
pass() {
echo "✅ PASS: $1"
PASS=$((PASS + 1))
}
fail() {
echo "❌ FAIL: $1"
FAIL=$((FAIL + 1))
}
test_endpoint() {
local method=$1
local path=$2
local data=$3
local expected_status=$4
local test_name=$5
local actual_status
if [ -n "$data" ]; then
actual_status=$(curl -s -o /dev/null -w "%{http_code}" \
-X "$method" \
-H "Content-Type: application/json" \
-d "$data" \
"$BASE_URL$path")
else
actual_status=$(curl -s -o /dev/null -w "%{http_code}" \
-X "$method" \
"$BASE_URL$path")
fi
if [ "$actual_status" -eq "$expected_status" ]; then
pass "$test_name (HTTP $actual_status)"
else
fail "$test_name (expected $expected_status, got $actual_status)"
fi
}
echo "=== 1. SQL Injection Tests ==="
# Test agent creation with SQL injection
test_endpoint POST "/api/v1/agents" \
'{"name":"test'"'"' OR '"'"'1'"'"'='"'"'1","displayName":"SQLi Test","role":"agent"}' \
400 \
"SQL injection in agent name rejected"
# Test session creation with malicious token
test_endpoint POST "/api/v1/sessions" \
'{"apiToken":"ah_live_XXXX'"'"'; DROP TABLE agents--"}' \
401 \
"SQL injection in token rejected"
echo ""
echo "=== 2. Header Injection Tests ==="
# Test XSS in headers
test_endpoint GET "/rooms" "" 401 "Missing auth header returns 401"
actual=$(curl -s -H "x-agent-id: <script>alert(1)</script>" "$BASE_URL/rooms" | grep -o "error" || echo "")
if [ -n "$actual" ]; then
pass "XSS in x-agent-id header rejected"
else
fail "XSS in x-agent-id header not properly rejected"
fi
echo ""
echo "=== 3. Rate Limit Tests ==="
# Burst 10 requests to healthz (should pass, allowlisted)
success_count=0
for i in {1..10}; do
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/healthz")
if [ "$status" -eq 200 ]; then
success_count=$((success_count + 1))
fi
done
if [ $success_count -eq 10 ]; then
pass "Healthz endpoint not rate-limited"
else
fail "Healthz endpoint incorrectly rate-limited ($success_count/10 succeeded)"
fi
# Burst 120 unauthenticated requests to /rooms (should hit rate limit)
# Rate limit is 100 req/min, so 120 should fail on some
rate_limited=0
for i in {1..120}; do
status=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/rooms")
if [ "$status" -eq 429 ]; then
rate_limited=1
break
fi
done
if [ $rate_limited -eq 1 ]; then
pass "Unauthenticated rate limit enforced (100 req/min)"
else
fail "Unauthenticated rate limit not enforced (expected 429 after 100 requests)"
fi
echo ""
echo "=== 4. CORS Tests ==="
# Test unauthorized origin
cors_header=$(curl -s -H "Origin: http://evil.com" -I "$BASE_URL/healthz" | grep -i "access-control-allow-origin" || echo "")
if [ -z "$cors_header" ]; then
pass "Unauthorized origin rejected by CORS"
else
fail "Unauthorized origin accepted by CORS: $cors_header"
fi
# Test allowed origin (localhost)
cors_header=$(curl -s -H "Origin: http://localhost:3000" -I "$BASE_URL/healthz" | grep -i "access-control-allow-origin" || echo "")
if [ -n "$cors_header" ]; then
pass "Allowed origin accepted by CORS"
else
fail "Allowed origin rejected by CORS"
fi
echo ""
echo "=== 5. Security Headers Tests ==="
# Check for security headers
headers=$(curl -s -I "$BASE_URL/healthz")
echo "$headers" | grep -q "x-frame-options: DENY" && pass "X-Frame-Options header present" || fail "X-Frame-Options header missing"
echo "$headers" | grep -q "referrer-policy: strict-origin" && pass "Referrer-Policy header present" || fail "Referrer-Policy header missing"
echo "$headers" | grep -q "content-security-policy:" && pass "CSP header present" || fail "CSP header missing"
# HSTS should be absent in Phase 1 (HTTP LAN)
echo "$headers" | grep -q "strict-transport-security:" && fail "HSTS enabled in Phase 1 (should be disabled)" || pass "HSTS disabled in Phase 1"
echo ""
echo "=== 6. Input Validation Tests ==="
# Test invalid UUID in room creation
test_endpoint POST "/rooms" \
'{"slug":"test-room","name":"Test","members":["not-a-uuid"]}' \
400 \
"Invalid UUID in members rejected"
# Test oversized message body (16KB limit)
oversized_body=$(printf 'A%.0s' {1..20000})
test_endpoint POST "/api/v1/sessions" \
"{\"apiToken\":\"$oversized_body\"}" \
401 \
"Oversized payload handled gracefully"
echo ""
echo "=== Summary ==="
echo "Passed: $PASS"
echo "Failed: $FAIL"
if [ $FAIL -eq 0 ]; then
echo "✅ All pen-tests passed"
exit 0
else
echo "❌ Some pen-tests failed"
exit 1
fi