Harden API security: input validation, safe auth extraction, new tests, and deploy config

Comprehensive security hardening from audit findings:
- Add validation tags to all DTO request structs (max lengths, ranges, enums)
- Replace unsafe type assertions with MustGetAuthUser helper across all handlers
- Remove query-param token auth from admin middleware (prevents URL token leakage)
- Add request validation calls in handlers that were missing c.Validate()
- Remove goroutines in handlers (timezone update now synchronous)
- Add sanitize middleware and path traversal protection (path_utils)
- Stop resetting admin passwords on migration restart
- Warn on well-known default SECRET_KEY
- Add ~30 new test files covering security regressions, auth safety, repos, and services
- Add deploy/ config, audit digests, and AUDIT_FINDINGS documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-02 09:48:01 -06:00
parent 56d6fa4514
commit 7690f07a2b
123 changed files with 8321 additions and 750 deletions

49
audit-digest-9.md Normal file
View File

@@ -0,0 +1,49 @@
# Digest 9: services (remaining), task package, testutil, validator, worker, pkg
### services/storage_service.go (184 lines)
- Line 75: UUID truncated to 8 chars — increased collision risk
- **SECURITY**: Line 137-138: filepath.Abs errors ignored — path traversal check could be bypassed
### services/subscription_service.go (659 lines)
- **PERFORMANCE**: Line 186-204: N+1 queries in getUserUsage — 3 queries per residence
- **SECURITY/BUSINESS**: Line 371: Apple validation failure grants 1-month free Pro
- **SECURITY/BUSINESS**: Line 381: Apple validation not configured grants 1-year free Pro
- **SECURITY/BUSINESS**: Line 429, 449: Same for Google — errors/misconfiguration grant free Pro
- Line 7: Uses stdlib "log" instead of zerolog
### services/task_button_types.go (85 lines) - Clean, uses predicates correctly
### services/task_service.go (1092 lines)
- **DATA INTEGRITY**: Line 601: If task update fails after completion creation, error only logged not returned — stale NextDueDate/InProgress
- Line 735: Goroutine in QuickComplete (service method) — inconsistent with synchronous CreateCompletion
- Line 773: Unbounded goroutine creation per user for notifications
- Line 790: Fail-open email notification on error (intentional but risky)
- **SECURITY**: Line 857-862: resolveImageFilePath has NO path traversal validation
### services/task_template_service.go (70 lines) - Errors returned raw (not wrapped with apperrors)
### services/user_service.go (88 lines) - Returns nil instead of empty slice (JSON null vs [])
### task/categorization/chain.go (359 lines) - Clean chain-of-responsibility
### task/predicates/predicates.go (217 lines)
- Line 210: IsRecurring requires Frequency preloaded — returns false without it
### task/scopes/scopes.go (270 lines)
- Line 118: ScopeOverdue doesn't exclude InProgress — differs from categorization chain
### task/task.go (261 lines) - Clean facade re-exports
### testutil/testutil.go (359 lines)
- Line 86: json.Marshal error ignored in MakeRequest
- Line 92: http.NewRequest error ignored
### validator/validator.go (103 lines) - Clean
### worker/jobs/email_jobs.go (118 lines) - Clean
### worker/jobs/handler.go (810 lines)
- Lines 95-106, 193-204: Direct DB access bypasses repository layer
- Line 627-635: Raw SQL with fmt.Sprintf (not currently user-supplied but fragile)
- Line 154, 251: O(N*M) lookup instead of map
### worker/scheduler.go (240 lines)
- Line 200-212: Cron schedules at fixed UTC times may conflict with smart reminder system — potential duplicate notifications
### pkg/utils/logger.go (132 lines) - Panic recovery bypasses apperrors.HTTPErrorHandler