# Issue #278: Implement CSRF protection on state-changing endpoints

## Objective

Implement CSRF protection for all state-changing endpoints (POST, PATCH, DELETE) to prevent CSRF attacks.

## Security Impact

**Vulnerable Endpoints:**

- Connection initiation (`POST /api/v1/federation/connections/initiate`)
- Connection acceptance (`POST /api/v1/federation/connections/:id/accept`)
- Agent spawn (`POST /api/v1/agents/spawn`)
- Identity linking (POST endpoints in auth module)

## Modern CSRF Protection Approaches

### Option 1: SameSite Cookie Attribute (Simplest)

- Set `SameSite=Strict` or `SameSite=Lax` on session cookies
- No code changes required if already using sessions
- Modern browser support
- **Limitation**: Doesn't protect against subdomain attacks

### Option 2: Double Submit Cookie Pattern

- Generate CSRF token, store in cookie and send in header
- Validate that cookie and header match
- No server-side session storage required
- Works well with stateless apps

### Option 3: Synchronizer Token Pattern

- Generate CSRF token per session
- Store in session, validate on each request
- Requires session storage
- Most secure but complex

## Recommended Approach

**Use Double Submit Cookie Pattern:**

1. Generate CSRF token on first authenticated request
2. Set token in httpOnly cookie
3. Client includes token in X-CSRF-Token header
4. Server validates cookie matches header

**Exempt signature-based endpoints:**

- Federation incoming connections (already signature-verified)
- Any public endpoints that don't require authentication

## Implementation Plan

### 1. Create CSRF Guard

```typescript
// src/common/guards/csrf.guard.ts
@Injectable()
export class CsrfGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();

    // Exempt GET, HEAD, OPTIONS (safe methods)
    if (["GET", "HEAD", "OPTIONS"].includes(request.method)) {
      return true;
    }

    // Get token from cookie and header
    const cookieToken = request.cookies["csrf-token"];
    const headerToken = request.headers["x-csrf-token"];

    // Validate tokens match
    if (!cookieToken || !headerToken || cookieToken !== headerToken) {
      throw new ForbiddenException("Invalid CSRF token");
    }

    return true;
  }
}
```

### 2. CSRF Token Generation Endpoint

```typescript
@Get('csrf-token')
getCsrfToken(@Res() response: Response): { token: string } {
  const token = crypto.randomBytes(32).toString('hex');
  response.cookie('csrf-token', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'strict',
  });
  return { token };
}
```

### 3. Apply Guard Globally (with exemptions)

```typescript
// main.ts
app.useGlobalGuards(new CsrfGuard());
```

Or per-controller/route:

```typescript
@UseGuards(CsrfGuard)
@Controller("api/v1/federation")
export class FederationController {
  // Endpoints automatically protected
}
```

### 4. Exempt Signature-Based Endpoints

```typescript
@Post('incoming/connect')
@SkipCsrf() // Custom decorator
async handleIncomingConnection() {
  // Signature verification provides authentication
}
```

## Alternative: Check Existing Protection

Before implementing, verify if CSRF protection already exists:

1. Check if session cookies use SameSite attribute
2. Check for existing CSRF middleware
3. Check authentication middleware configuration

## Testing Requirements

1. Test CSRF token generation endpoint
2. Test protected endpoint rejects missing token
3. Test protected endpoint rejects mismatched token
4. Test protected endpoint accepts valid token
5. Test exempted endpoints work without token
6. Test safe methods (GET) work without token

## Progress

- [ ] Create scratchpad
- [ ] Check for existing CSRF protection
- [ ] Decide on implementation approach
- [ ] Create CSRF guard
- [ ] Create token generation endpoint
- [ ] Apply guard to controllers
- [ ] Add exemptions for signature-based endpoints
- [ ] Add tests
- [ ] Update frontend to include tokens
- [ ] Run quality gates
- [ ] Commit and push
- [ ] Close issue

## Notes

**Important Considerations:**

1. Don't break existing API consumers
2. Ensure frontend can get and use tokens
3. Document token usage for API clients
4. Consider backward compatibility

**Scope Decision:**
Given this is backend-focused and the frontend integration is complex, consider:

- Implementing SameSite cookie protection (simpler, immediate benefit)
- OR implementing CSRF guard with proper exemptions
- Document that frontend integration is required for full protection
