PoP Authentication Security Fixes
SEC-0001: PoP Authentication Security Fixes
| Date | Author | Severity |
|---|---|---|
| 2026-02-26 | Fabian Beyerlein | see individual issues |
Issues Fixed
1. Parser Input Validation (HIGH)
Problem: ParsePoP() accepted unbounded input, enabling DoS attacks
- No size limits on header or individual fields
- No format validation (UUID, base64)
- Silent handling of malformed data
Fix:
- Added max lengths: header 1KB, kid/nonce 128B, signature 512B
- UUID validation for
kidandnoncefields - Base64 validation for signature
- Timestamp bounds checking (0 to year 9999)
- Duplicate field detection
- Returns specific errors for each validation failure
Files:
backend/pkg/pop/pop.gobackend/pkg/pop/pop_test.go(unit tests)
Verification:
go test -fuzz=FuzzParsePoP -fuzztime=5m ./backend/pkg/pop
# Result: 53M+ iterations, 0 crashes, 220 interesting inputs
2. Nonce Replay Race Condition (CRITICAL)
Problem: Check-then-store pattern allowed replay attacks under concurrent load
// Old code - race window:
if cache.Exists(nonce) { return error }
cache.Store(nonce) // ← Two requests can both pass
Fix: Atomic StoreIfNotExists() operation
// New code - atomic:
stored, err := cache.StoreIfNotExists(nonce, ttl)
if !stored { return "replay detected" }
Files:
backend/apps/nexus/modules/adapter/domain/cache.go(interface)backend/apps/nexus/modules/adapter/infra/redis_nonce_cache.go(Redis SETNX)backend/apps/nexus/modules/adapter/app/adapter_auth.go(usage)
3. Redis TTL Bug (MEDIUM)
Problem: Hardcoded 15min TTL instead of using configurable parameter
- Replay window 3x larger than intended
- Security policy not enforced
Fix: Use ttl parameter in Redis SET command
// Old: c.redisClient.Set(ctx, key, "1", 15*time.Minute)
// New: c.redisClient.Set(ctx, key, "1", ttl)
Files:
backend/apps/nexus/modules/adapter/infra/redis_nonce_cache.go
4. Silent Cache Failure (MEDIUM)
Problem: Authentication continued even if nonce storage failed
- Defeats replay protection on cache errors
- Fail-open security vulnerability
Fix: Return error if nonce cannot be stored
stored, err := cache.StoreIfNotExists(...)
if err != nil {
return errors.New("nonce validation failed")
}
Files:
backend/apps/nexus/modules/adapter/app/adapter_auth.go