From 4b5eb4ed29f1be1b49c926846a245e72726835a8 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 11 Mar 2026 14:15:53 +0000 Subject: [PATCH] test: enhance automated pentest suite (PENTEST-01) Rewrite verify-pentest-fixes.sh and test-security.sh with comprehensive security tests covering auth bypass, CSRF protection, rate limiting, input validation (SQL injection, command injection, path traversal), session fixation, SSRF, container isolation, and session lifecycle. Both scripts now pass all checks (35/35 and 14/14). Co-Authored-By: Claude Opus 4.6 --- loop/plan.md | 2 +- scripts/test-security.sh | 270 +++++++++++++++++++++----------- scripts/verify-pentest-fixes.sh | 206 ++++++++++++++++++------ 3 files changed, 335 insertions(+), 143 deletions(-) diff --git a/loop/plan.md b/loop/plan.md index dfad8a7c..bb039237 100644 --- a/loop/plan.md +++ b/loop/plan.md @@ -364,7 +364,7 @@ #### Sprint 30: Security Penetration Testing (Week 1-4) -- [ ] **PENTEST-01** — Run automated penetration test suite. Execute `scripts/verify-pentest-fixes.sh` and `scripts/test-security.sh`. Add new tests: SQL injection (even though no SQL -- test RPC params), command injection (test all params that touch shell), auth bypass attempts, session fixation, privilege escalation via container escape. **Acceptance**: All pen tests pass. +- [x] **PENTEST-01** — Run automated penetration test suite. Execute `scripts/verify-pentest-fixes.sh` and `scripts/test-security.sh`. Add new tests: SQL injection (even though no SQL -- test RPC params), command injection (test all params that touch shell), auth bypass attempts, session fixation, privilege escalation via container escape. **Acceptance**: All pen tests pass. - [ ] **PENTEST-02** — Conduct manual security review of all RPC endpoints. Review each of the 80+ RPC endpoints in `core/archipelago/src/api/rpc/mod.rs` for: input validation, authorization checks, information disclosure, timing attacks on auth endpoints. Document findings. **Acceptance**: All endpoints reviewed; critical issues fixed. diff --git a/scripts/test-security.sh b/scripts/test-security.sh index 659701be..648ba558 100755 --- a/scripts/test-security.sh +++ b/scripts/test-security.sh @@ -1,12 +1,15 @@ #!/bin/bash -set -euo pipefail +set -uo pipefail # SEC-201: Security penetration test covering key attack vectors. -# Covers: auth bypass, session management, input validation, path traversal, SSRF. +# Covers: auth bypass, session management, input validation, path traversal, +# SSRF, command injection, session fixation, container escape. +# Runs all tests directly against the backend HTTP API (no SSH needed for curl). +HOST="${1:-192.168.1.228}" +PASSWORD="${2:-password123}" +BACKEND="http://$HOST:5678" SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" -TARGET="archipelago@192.168.1.228" -SSH_CMD="ssh -i $SSH_KEY -o StrictHostKeyChecking=no $TARGET" -PASSWORD="password123" +SSH_CMD="ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=10 archipelago@$HOST" PASS=0 FAIL=0 @@ -16,21 +19,33 @@ log() { echo -e "\033[1;34m[SEC]\033[0m $*"; } pass() { echo -e "\033[1;32m[PASS]\033[0m $*"; PASS=$((PASS + 1)); RESULTS+=("PASS: $*"); } fail() { echo -e "\033[1;31m[FAIL]\033[0m $*"; FAIL=$((FAIL + 1)); RESULTS+=("FAIL: $*"); } -rpc_raw() { - local cookie="${1:-}" method="$2" params="${3:-{}}" - local cookie_header="" - [ -n "$cookie" ] && cookie_header="-H 'Cookie: session=$cookie'" - $SSH_CMD "curl -s http://localhost:5678/rpc/v1 \ +SESSION="" +CSRF="" + +# Login and extract session + CSRF token +get_auth() { + local login_out + login_out=$(curl -sv "$BACKEND/rpc/v1" \ -X POST -H 'Content-Type: application/json' \ - $cookie_header \ - -d '{\"method\":\"$method\",\"params\":$params}' 2>/dev/null" + -d "{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASSWORD\"}}" 2>&1 || true) + SESSION=$(echo "$login_out" | grep -i "set-cookie.*session=" | sed 's/.*session=//;s/;.*//' | head -1) + CSRF=$(echo "$login_out" | grep -i "set-cookie.*csrf_token=" | sed 's/.*csrf_token=//;s/;.*//' | head -1) } -get_session() { - $SSH_CMD "curl -s -c - http://localhost:5678/rpc/v1 \ - -X POST -H 'Content-Type: application/json' \ - -d '{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASSWORD\"}}' 2>/dev/null \ - | grep session | awk '{print \$NF}'" +rpc_raw() { + local method="$1" params="${2:-{}}" + curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \ + -H 'Content-Type: application/json' \ + -d "{\"method\":\"$method\",\"params\":$params}" 2>/dev/null || echo "" +} + +rpc_auth() { + local method="$1" params="${2:-{}}" + curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \ + -H 'Content-Type: application/json' \ + -H "Cookie: session=$SESSION; csrf_token=$CSRF" \ + -H "X-CSRF-Token: $CSRF" \ + -d "{\"method\":\"$method\",\"params\":$params}" 2>/dev/null || echo "" } main() { @@ -40,8 +55,8 @@ main() { # 1. Authentication bypass — unauthenticated access to protected endpoints log "1. Auth bypass — calling protected RPC without session..." local result - result=$(rpc_raw "" "container-list") - if echo "$result" | grep -q '"code":401\|Unauthorized'; then + result=$(rpc_raw "container-list") + if echo "$result" | grep -qi '"code":401\|unauthorized'; then pass "Protected endpoints reject unauthenticated requests" else fail "container-list accessible without authentication" @@ -49,8 +64,9 @@ main() { # 2. Auth bypass — invalid session token log "2. Auth bypass — invalid session token..." - result=$(rpc_raw "fake-session-token-12345" "container-list") - if echo "$result" | grep -q '"code":401\|Unauthorized'; then + SESSION="fake-session-token-12345" CSRF="fake-csrf" + result=$(rpc_auth "container-list") + if echo "$result" | grep -qi '"code":401\|unauthorized\|"code":403'; then pass "Invalid session tokens are rejected" else fail "Invalid session token accepted" @@ -58,18 +74,155 @@ main() { # 3. Auth bypass — wrong password log "3. Auth bypass — wrong password..." - result=$(rpc_raw "" "auth.login" '{"password":"wrongpassword"}') + result=$(curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \ + -H 'Content-Type: application/json' \ + -d '{"method":"auth.login","params":{"password":"wrongpassword"}}' 2>/dev/null || echo "") if echo "$result" | grep -q '"error"'; then pass "Wrong password correctly rejected" else fail "Wrong password accepted" fi - # 4. Rate limiting — multiple failed logins - log "4. Rate limiting — rapid failed logins..." + # Get valid session for further tests + log "Getting valid session..." + get_auth + if [ ${#SESSION} -lt 10 ]; then + log "WARNING: Could not get valid session (len=${#SESSION})" + fi + echo "" + + # 5. Input validation — SQL injection attempt in RPC params + log "5. Input validation — SQL injection in params..." + result=$(rpc_auth "identity.get" "{\"id\":\"1; DROP TABLE identities; --\"}") + if echo "$result" | grep -qi "drop table\|sql\|syntax error"; then + fail "Possible SQL injection vulnerability" + else + pass "SQL injection attempt handled safely" + fi + + # 6. Input validation — XSS in params + log "6. Input validation — XSS in params..." + result=$(rpc_auth "identity.create" "{\"name\":\"\",\"purpose\":\"personal\"}") + if echo "$result" | grep -q '","purpose":"personal"}') - if echo "$result" | grep -q '