Skip to content

[Security P0] Implement comprehensive rate limiting across all API endpoints (#132)#191

Open
om952 wants to merge 12 commits into
OpenScanAI:masterfrom
om952:rate-limiting
Open

[Security P0] Implement comprehensive rate limiting across all API endpoints (#132)#191
om952 wants to merge 12 commits into
OpenScanAI:masterfrom
om952:rate-limiting

Conversation

@om952

@om952 om952 commented Jun 16, 2026

Copy link
Copy Markdown

Thinking Path

 > - Paperclip orchestrates AI agents for zero-human companies                                                                                                          
 > - The API server handles all agent and board operations via REST endpoints                                                                                           
 > - No rate limiting exists on any endpoint, enabling DDoS, brute-force, and resource exhaustion                                                                       
 > - Issue #132 (Security P0) requires comprehensive rate limiting across all API endpoints                                                                             
 > - This pull request implements tiered rate limiting with Redis + LRU fallback                                                                                        
 > - The benefit is protection against API abuse while maintaining availability via fail-open behavior                                                                  
                                                                                                                                                                        
What Changed                                                                                                                                                        
                                                                                                                                                                        
 - Added ioredis dependency for optional Redis-backed distributed rate limiting                                                                                         
 - Created server/src/middleware/rate-limiter.ts with 5-tier rate limiting:                                                                                             
   - Public: 60/min, Authenticated: 120/min, Heartbeat: 120/min, Write: 30/min, Admin: 300/min                                                                          
 - Implemented LRU fallback store (10k entries) when Redis is unavailable                                                                                               
 - Added config schema changes in packages/shared/src/config-schema.ts for redis and rateLimiting settings                                                              
 - Wired rate limiter into server/src/index.ts (Redis client creation) and server/src/app.ts (middleware mounting)                                                      
 - Health routes bypass rate limiting for load balancer health checks                                                                                                   
 - Added standard rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Tier                                                     
 - Implemented fail-open behavior (configurable via PAPERCLIP_RATE_LIMITING_FAIL_OPEN)                                                                                  
 - Path normalization for parameterized routes (UUIDs, numeric IDs → :id) to prevent per-endpoint gaming                                                                
 - Added 15 comprehensive unit tests in server/src/tests/rate-limiter.test.ts                                                                                           
                                                                                                                                                                        
 Verification                                                                                                                                                        
                                                                                                                                                                        
 bash                                                                                                                                                                   
 Start server                                                                                                                                                           
 cd /Users/omkandpal/Levi && pnpm dev                                                                                                                                   
 Check health endpoint (no rate limiting)                                                                                                                               
 curl -i http://localhost:3100/api/health                                                                                                                               
 Should return 200 without X-RateLimit-* headers                                                                                                                        
 Check rate limit headers on protected endpoint                                                                                                                         
 curl -i http://localhost:3100/api/companies                                                                                                                            
 Should show X-RateLimit-Limit: 60, X-RateLimit-Tier: public                                                                                                            
 Test rate limit blocking (exhaust 60 requests)                                                                                                                         
 for i in {1..65}; do                                                                                                                                                   
   curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3100/api/companies                                                                                         
 done                                                                                                                                                                   
 First 60: 200, requests 61+: 429                                                                                                                                       
 Run unit tests                                                                                                                                                         
 pnpm test:run -- server/src/tests/rate-limiter.test.ts                                                                                                                 
 15 tests passing                                                                                                                                                       
 Typecheck                                                                                                                                                              
 pnpm --filter @paperclipai/server typecheck                                                                                                                            
 Passes                                                                                                                                                                 
                                                                                                                                                                        
 Risks                                                                                                                                                               
                                                                                                                                                                        
 - Low risk for local dev: LRU fallback works without Redis, no external dependency required                                                                            
 - Redis connection failure: Fail-open by default — if Redis goes down, requests are allowed (configurable to fail-closed)                                              
 - Memory usage: LRU store capped at 10k entries, oldest evicted when full                                                                                              
 - Path normalization edge cases: Some custom ID formats may not be normalized, could allow limited per-endpoint gaming                                                 
 - No migration needed: This is additive middleware, no database or schema changes required           

Closes #132

om kandpal and others added 12 commits May 27, 2026 17:16
- Added section 9: Error Handling Standards
- Rules: try/catch wrapper, logError call, exact error response shape,
  HTTP status codes (500/400/404), logError location
- Renumbered subsequent sections (10-13)
## Problem
Agent creation fails with adapter errors when agents try to create issues.
CTO agent specifically gets: adapter_failed, tool_call_id errors, max iterations reached.

## Root Causes
1. Missing Permissions - Only CEO had canCreateAgents permission
2. Process Adapter Missing JWT - No supportsLocalAgentJwt flag
3. Missing API Keys - Agents created without API keys
4. Missing tool_call_id - ACPX adapter events lacked toolCallId

## Fixes
- Extended defaultPermissionsForRole() to include leadership roles (CEO, CTO, CFO, COO, VP, Director)
- Added applyDefaultAgentCreateGrant() to auto-grant agents:create permission in DB
- Added auto-generation of API keys on agent creation
- Added supportsLocalAgentJwt: true to process adapter with PAPERCLIP_API_KEY injection
- Added toolCallId validation and fallback ID generation in ACPX adapter

## Tests
- 75 tests passing across modified areas
- New e2e tests: agent-issue-creation-e2e.test.ts (4 tests)
- New full e2e tests: agent-issue-creation-full-e2e.test.ts (4 tests with real DB)

Closes OpenScanAI#4
… API endpoints

- Add ioredis dependency for Redis-backed rate limiting
- Create rate-limiter middleware with 5 tiers: public, authenticated, heartbeat, write, admin
- Implement LRU fallback store when Redis is unavailable
- Add config schema changes for redis and rateLimiting settings
- Wire rate limiter into app.ts and index.ts startup
- Health routes bypass rate limiting for load balancer checks
- Standard rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Tier
- Fail-open behavior when Redis is unavailable (configurable)
- Path normalization for parameterized routes to prevent per-endpoint gaming

Closes OpenScanAI#132
- Tier detection tests: public, authenticated, write, admin, heartbeat
- Rate limiting behavior: under limit, over limit, window reset
- Middleware tests: headers, 429 response, fail-open, fail-closed
- Path normalization tests: UUID and numeric ID grouping
- Fix health endpoint tier detection (returns public for unauthenticated)

All 15 tests passing
siddhijadhav27 pushed a commit to siddhijadhav27/Levi that referenced this pull request Jun 17, 2026
Change onChange handler from v || undefined to v ?? "" so empty
strings don't become undefined and crash downstream .trim() calls.

Fixes OpenScanAI#191

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security P0] Implement comprehensive rate limiting across all API endpoints

1 participant