-
Notifications
You must be signed in to change notification settings - Fork 519
Description
[TESTING][SECURITY]: CSRF protection manual test plan (tokens, SameSite cookies, origin validation)
Goal
Produce a comprehensive manual test plan for validating Cross-Site Request Forgery (CSRF) attacks are prevented through SameSite cookie attributes, secure cookie configuration, and token-based authentication design.
Why Now?
Security testing is critical for GA release:
- Production Readiness: Security must be validated before release
- Compliance: Required by security standards and audits
- Defense in Depth: Validates multiple protection layers
- Attack Mitigation: Prevents common exploitation techniques
- User Trust: Security issues erode confidence
Scope Clarification
What Exists
| Feature | Status | Location |
|---|---|---|
| SameSite cookie attribute | ✅ Implemented | config.py:484 - defaults to "lax" |
| HttpOnly cookie attribute | ✅ Implemented | utils/security_cookies.py:66 |
| Secure cookie attribute | ✅ Implemented | utils/security_cookies.py:67 (production/config) |
| JWT Bearer token auth | ✅ Primary API auth | Header-based, not cookie-based |
| Cookie-based admin UI auth | ✅ Implemented | utils/security_cookies.py:62-70 |
What Does NOT Exist
| Feature | Status |
|---|---|
| Explicit CSRF token middleware | ❌ Not implemented |
/api/csrf-token endpoint |
❌ Does not exist |
X-CSRF-Token header validation |
❌ Not implemented |
| Double-submit cookie pattern | ❌ Not implemented |
| Origin/Referer header validation | ❌ Not implemented |
CSRF Protection Strategy
The gateway uses a token-based authentication design that provides inherent CSRF protection:
- JSON API: Uses
Authorization: Bearer <token>header - not vulnerable to CSRF as browsers don't auto-attach custom headers - Admin UI: Uses
jwt_tokencookie withSameSite=laxattribute - browser prevents cookie from being sent on cross-origin POST requests
User Stories
Story 1: SameSite Cookie Protection
As a security administrator
I want session cookies to use SameSite attribute
So that cookies are not sent with cross-origin POST requests
Acceptance Criteria
Feature: SameSite cookie protection
Scenario: Admin UI cookie has SameSite=Lax
When a user logs into the admin UI
Then the jwt_token cookie should include SameSite=lax
Scenario: Cross-origin POST doesn't include cookies
When a cross-origin POST request is made
Then session cookies should not be sent (browser enforcement)Story 2: Secure Cookie Attributes
As a security administrator
I want cookies to have proper security attributes
So that cookie theft and injection attacks are prevented
Acceptance Criteria
Feature: Secure cookie attributes
Scenario: HttpOnly prevents JavaScript access
When the jwt_token cookie is set
Then it should include HttpOnly attribute
Scenario: Secure flag on HTTPS
When running in production mode
Then cookies should include Secure attributeStory 3: Bearer Token API Protection
As a security administrator
I want API endpoints to use Bearer token authentication
So that CSRF attacks cannot forge API requests
Acceptance Criteria
Feature: Bearer token protection
Scenario: API rejects cookie-only auth
When a request is made with only cookies (no Authorization header)
Then the API should reject with 401 Unauthorized
Scenario: API accepts Bearer token
When a request includes Authorization: Bearer <token>
Then the request should be processedArchitecture
┌─────────────────────────────────────────────────────────────────────┐
│ CSRF Protection Strategy │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ JSON API Protection (Primary) │ │
│ │ │ │
│ │ • Uses Authorization: Bearer <token> header │ │
│ │ • Browsers don't auto-attach custom headers │ │
│ │ • Cross-origin requests cannot include auth │ │
│ │ • CSRF not applicable for header-based auth │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Admin UI Protection (Cookie-based) │ │
│ │ │ │
│ │ Cookie: jwt_token │ │
│ │ ├── SameSite=lax (blocks cross-origin POST) │ │
│ │ ├── HttpOnly (prevents JS access) │ │
│ │ ├── Secure (HTTPS only in production) │ │
│ │ └── Path=/ (scoped to app) │ │
│ │ │ │
│ │ HTMX requests read cookie and send as header │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ NOT Implemented (Out of Scope) │ │
│ │ │ │
│ │ ✗ CSRF token generation/validation │ │
│ │ ✗ Origin/Referer header checking │ │
│ │ ✗ Double-submit cookie pattern │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Test Environment Setup
# Start the docker compose stack
docker compose up -d
# Verify health
curl http://localhost:8080/health
# Register a test user
curl -X POST -H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"TestPassword123!"}' \
http://localhost:8080/auth/email/register
# Extract token from response
export TOKEN="<token_from_response>"Test Cases
TC-CSRF-001: SameSite Cookie Attribute
Objective: Verify cookies have SameSite attribute
Steps:
# Step 1: Login via admin UI and check Set-Cookie header
curl -s -D - -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]&password=YourPassword123!" \
http://localhost:8080/admin/login 2>&1 | grep -i "set-cookie"
# Look for: SameSite=Lax (or Strict)Expected Results:
- Cookie includes
SameSite=laxorSameSite=strict - Default configuration is "lax" (see
config.py:484)
TC-CSRF-002: HttpOnly Cookie Attribute
Objective: Verify cookies have HttpOnly attribute
Steps:
# Step 1: Check cookie attributes after login
curl -s -D - -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]&password=YourPassword123!" \
http://localhost:8080/admin/login 2>&1 | grep -i "set-cookie"
# Look for: HttpOnly attributeExpected Results:
- jwt_token cookie includes
HttpOnly - JavaScript cannot access the cookie
TC-CSRF-003: Secure Cookie Attribute (HTTPS)
Objective: Verify cookies have Secure attribute on HTTPS
Steps:
# Step 1: Check environment setting
# In production: ENVIRONMENT=production or SECURE_COOKIES=true
# Step 2: Login over HTTPS and verify
curl -s -D - -k -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]&password=YourPassword123!" \
https://localhost:8443/admin/login 2>&1 | grep -i "set-cookie"
# Look for: Secure attributeExpected Results:
- HTTPS cookies include
Secureattribute in production - Cookies not sent over HTTP in production mode
TC-CSRF-004: API Bearer Token Requirement
Objective: Verify JSON API requires Bearer token, not cookies
Steps:
# Step 1: Try API with only cookies (should fail)
curl -s -w "\nStatus: %{http_code}\n" \
-b "jwt_token=some-token" \
http://localhost:8080/gateways
# Step 2: Try API with Bearer token (should succeed)
curl -s -w "\nStatus: %{http_code}\n" \
-H "Authorization: Bearer $TOKEN" \
http://localhost:8080/gatewaysExpected Results:
- Cookie-only request: 401 Unauthorized
- Bearer token request: 200 OK with data
TC-CSRF-005: Cross-Origin Request Simulation
Objective: Verify SameSite blocks cross-origin POST with cookies
Steps:
# Step 1: Simulate cross-origin POST (Origin header from different domain)
curl -s -w "\nStatus: %{http_code}\n" \
-X POST \
-H "Origin: http://evil.com" \
-H "Content-Type: application/json" \
-b "jwt_token=$COOKIE_TOKEN" \
-d '{"name":"test"}' \
http://localhost:8080/gateways
# Note: In a real browser, SameSite=lax would prevent the cookie
# from being sent at all on cross-origin POST. This curl test
# simulates what would happen if the cookie was somehow sent.Expected Results:
- Request fails or is rejected
- Browser enforcement prevents cookie sending on cross-origin POST
TC-CSRF-006: Admin UI Form Submission
Objective: Verify admin UI forms work with cookie auth
Steps:
# Step 1: Login to admin UI
curl -s -c /tmp/cookies.txt -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]&password=YourPassword123!" \
http://localhost:8080/admin/login
# Step 2: Access admin page with cookie
curl -s -b /tmp/cookies.txt \
http://localhost:8080/admin/ | head -50Expected Results:
- Login sets jwt_token cookie
- Subsequent requests with cookie are authenticated
- Same-origin requests work correctly
TC-CSRF-007: GET Requests Not State-Changing
Objective: Verify GET requests don't modify state
Steps:
# Step 1: Verify GET endpoints are read-only
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/gateways | jq 'length'
# Step 2: Verify no state change from GET
# (Idempotent - multiple calls return same result)Expected Results:
- GET requests are read-only
- No state modification possible via GET
- Safe from CSRF by design (safe method)
TC-CSRF-008: Cookie Configuration Check
Objective: Verify cookie security configuration
Steps:
# Step 1: Check default configuration
grep -n "cookie_samesite\|secure_cookies" \
mcpgateway/config.py
# Expected:
# cookie_samesite: str = Field(default="lax")
# secure_cookies: bool = Field(default=False) # True in productionExpected Results:
cookie_samesitedefaults to "lax"secure_cookiesconfigurable via environment
Test Matrix
| Test Case | SameSite | HttpOnly | Secure | Bearer | Cookie Auth |
|---|---|---|---|---|---|
| TC-CSRF-001 | ✓ | ||||
| TC-CSRF-002 | ✓ | ||||
| TC-CSRF-003 | ✓ | ||||
| TC-CSRF-004 | ✓ | ✓ | |||
| TC-CSRF-005 | ✓ | ✓ | |||
| TC-CSRF-006 | ✓ | ||||
| TC-CSRF-007 | ✓ | ||||
| TC-CSRF-008 | ✓ | ✓ |
Success Criteria
- All 8 test cases pass
- jwt_token cookie has SameSite=lax attribute
- jwt_token cookie has HttpOnly attribute
- jwt_token cookie has Secure attribute in production
- JSON API requires Bearer token (not cookie-only)
- Admin UI works with cookie authentication
- GET requests are safe/idempotent
Related Files
mcpgateway/utils/security_cookies.py- Cookie security configuration (lines 62-70)mcpgateway/config.py:484-cookie_samesitesetting (default: "lax")mcpgateway/config.py-secure_cookiessettingmcpgateway/admin.py- Admin UI login/logout handlersmcpgateway/templates/admin.html- Admin UI template
What This Test Plan Does NOT Cover
The following CSRF protections are NOT implemented in the gateway:
- Explicit CSRF tokens - No
/csrf-tokenendpoint orX-CSRF-Tokenheader validation - Origin/Referer validation - Server does not validate these headers
- Double-submit cookie pattern - Not implemented
The gateway relies on:
- Bearer token authentication for APIs (inherently CSRF-safe)
- SameSite cookies for admin UI (browser-enforced protection)
If explicit CSRF token protection is needed, it would require new implementation.
Related Issues
- None identified