# HoneyDue Go Backend — Deep Audit Findings **Date**: 2026-03-01 **Scope**: All non-test `.go` files under `honeyDueAPI-go/` **Agents**: 9 parallel audit agents covering security, authorization, data integrity, concurrency, performance, error handling, architecture compliance, API contracts, and cross-cutting logic --- ## Summary | Audit Area | Critical | Bug | Race Cond. | Logic Error | Silent Failure | Warning | Fragile | Performance | Total | |---|---|---|---|---|---|---|---|---|---| | Security & Input Validation | 7 | 12 | — | — | — | 17 | — | — | 36 | | Authorization & Access Control | 6 | 6 | — | — | — | 9 | — | — | 21 | | Data Integrity (GORM) | 7 | 7 | 3 | — | — | 11 | — | — | 28 | | Concurrency & Race Conditions | 1 | 4 | 3 | — | — | 10 | — | — | 18 | | Performance & Query Efficiency | — | — | — | — | — | 1 | — | 19 | 20 | | Error Handling & Panic Safety | 17 | 10 | — | — | 9 | 12 | — | — | 48 | | Architecture Compliance | — | 12 | — | — | — | 11 | — | — | 23 | | API Contract & Validation | — | 19 | — | — | — | 30 | — | — | 49 | | Cross-Cutting Logic | 5 | 5 | 3 | 3 | 1 | — | 4 | — | 21 | | **Total (raw)** | **43** | **75** | **9** | **3** | **10** | **101** | **4** | **19** | **264** | --- ## Audit 1: Security & Input Validation ### SEC-01 | CRITICAL | Apple JWS payload decoded without signature verification - **File**: `internal/handlers/subscription_webhook_handler.go:190-192` - **What**: `decodeAppleSignedPayload` splits the JWS token and base64-decodes the payload directly. The comment on line 190 explicitly says "we're trusting Apple's signature for now." `VerifyAppleSignature` exists but is never called from the handler flow. - **Impact**: An attacker can craft a fake Apple webhook with arbitrary notification data (subscribe/renew/refund), granting or revoking Pro subscriptions for any user who has ever made a purchase. ### SEC-02 | CRITICAL | Google Pub/Sub webhook always returns true (unauthenticated) - **File**: `internal/handlers/subscription_webhook_handler.go:787-793` - **What**: `VerifyGooglePubSubToken` unconditionally returns `true`. The Google webhook endpoint `HandleGoogleWebhook` never calls this function at all. Any HTTP client can POST arbitrary subscription events. - **Impact**: An attacker can forge Google subscription events to grant themselves Pro access, cancel other users' subscriptions, or trigger arbitrary downgrades. ### SEC-03 | CRITICAL | GoAdmin password reset to "admin" on every migration - **File**: `internal/database/database.go:372-382` - **What**: Line 373 does `INSERT ON CONFLICT DO NOTHING`, but line 379-382 unconditionally `UPDATE goadmin_users SET password = WHERE username = 'admin'`. Every time migrations run, the GoAdmin password is reset to "admin". - **Impact**: The admin panel is permanently accessible with `admin/admin` credentials. Even if the password is changed, the next deploy resets it. ### SEC-04 | CRITICAL | Next.js admin password reset to "admin123" on every migration - **File**: `internal/database/database.go:447-463` - **What**: Lines 458-463 unconditionally update the admin@honeydue.com password to the bcrypt hash of "admin123" on every migration. The log message on line 463 even says "Updated admin@honeydue.com password to admin123." - **Impact**: The admin API is permanently accessible with hardcoded credentials. Any attacker who discovers the endpoint can access full admin functionality. ### SEC-05 | CRITICAL | SQL injection via SortBy in all admin list endpoints - **File**: `internal/admin/handlers/admin_user_handler.go:86-88` - **What**: `sortBy = filters.SortBy` is concatenated directly into `query.Order(sortBy + " " + filters.GetSortDir())` without any allowlist validation. This pattern is repeated across every admin list handler (admin_user, auth_token, completion, contractor, document, device, notification, etc.). - **Impact**: An authenticated admin can inject arbitrary SQL via the `sort_by` query parameter, e.g., `sort_by=created_at; DROP TABLE auth_user; --`, achieving full database read/write. ### SEC-06 | CRITICAL | Apple validation failure grants 1 month free Pro - **File**: `internal/services/subscription_service.go:371` - **What**: When Apple receipt validation returns a non-fatal error (network timeout, transient failure), the code falls through to `expiresAt = time.Now().UTC().AddDate(0, 1, 0)` -- granting 1 month of Pro. Line 381 grants 1 year when Apple IAP is not configured. - **Impact**: An attacker can send any invalid receipt data, trigger a validation error, and receive free Pro access. Repeating monthly yields indefinite free Pro. ### SEC-07 | CRITICAL | Google validation failure grants 1 month free Pro; not configured grants 1 year - **File**: `internal/services/subscription_service.go:429-449` - **What**: Same pattern as Apple. Line 430: non-fatal Google validation error gives 1-month fallback. Line 449: unconfigured Google client gives 1 year. An attacker sending a garbage `purchaseToken` with `platform=android` triggers the fallback. - **Impact**: Free Pro subscription for any user by sending invalid purchase data. ### SEC-08 | BUG | Token slice panic on short tokens - **File**: `internal/middleware/auth.go:66` - **What**: `token[:8]+"..."` in the debug log message will panic with an index-out-of-range if the token string is fewer than 8 characters. There is no length check before slicing. - **Impact**: A malformed Authorization header with a valid scheme but very short token causes a server panic (500) and potential DoS. ### SEC-09 | BUG | Path traversal in resolveFilePath - **File**: `internal/handlers/media_handler.go:156-171` - **What**: `resolveFilePath` uses `strings.TrimPrefix` followed by `filepath.Join(uploadDir, relativePath)`. If the stored URL contains `../` sequences (e.g., `/uploads/../../../etc/passwd`), `filepath.Join` resolves them and `c.File()` serves the resulting path. There is no `filepath.Abs` containment check (unlike `storage_service.Delete`). - **Impact**: If an attacker can control a stored URL (e.g., via SQL injection or a compromised document record), they can read arbitrary files from the server filesystem. ### SEC-10 | BUG | Path traversal in resolveImageFilePath (task service) - **File**: `internal/services/task_service.go:850-862` - **What**: Identical path traversal vulnerability to media_handler's `resolveFilePath`. No validation that the resolved path stays within the upload directory. - **Impact**: Arbitrary file read if stored URLs are manipulated. ### SEC-11 | BUG | Path traversal check bypassed when filepath.Abs errors - **File**: `internal/services/storage_service.go:137-138` - **What**: `absUploadDir, _ := filepath.Abs(s.cfg.UploadDir)` and `absFilePath, _ := filepath.Abs(fullPath)` both silently discard errors. If `filepath.Abs` fails, both return empty strings, `strings.HasPrefix("", "")` is true, and the path traversal check passes. - **Impact**: Under unusual filesystem conditions, the path containment check becomes ineffective, allowing deletion of arbitrary files. ### SEC-12 | BUG | Nil pointer panic after WebSocket upgrade failure - **File**: `internal/monitoring/handler.go:116-119` - **What**: When `upgrader.Upgrade` fails, `conn` is nil but execution continues to `defer conn.Close()`, causing a nil pointer panic. - **Impact**: Server panic on any failed WebSocket upgrade attempt. ### SEC-13 | BUG | Missing return after context cancellation causes goroutine spin - **File**: `internal/monitoring/handler.go:177` - **What**: The `case <-ctx.Done():` block has no `return` statement, so after the context is cancelled, the `for` loop immediately re-enters the `select` and spins indefinitely. - **Impact**: 100% CPU usage on one goroutine for every WebSocket connection that disconnects. The goroutine never exits, leaking resources. ### SEC-14 | BUG | Nil pointer dereference when cache is nil - **File**: `internal/admin/handlers/lookup_handler.go:30-32` - **What**: `cache := services.GetCache(); if cache == nil { }` has an empty body, then immediately calls `cache.CacheCategories()`. If cache is nil, this panics. Same pattern at lines 50-52 for priorities. - **Impact**: Server panic in admin lookup handlers when Redis is unavailable. ### SEC-15 | BUG | Panic on short reset tokens - **File**: `internal/admin/handlers/password_reset_code_handler.go:85` - **What**: `code.ResetToken[:8] + "..." + code.ResetToken[len-4:]` panics with index out of range if the reset token is fewer than 8 characters. - **Impact**: Admin panel crash when viewing short reset codes. ### SEC-16 | BUG | Race condition in Apple legacy receipt validation - **File**: `internal/services/iap_validation.go:381-386` - **What**: `c.sandbox = true` mutates the struct field, calls `validateLegacyReceipt`, then `c.sandbox = false`. If two concurrent requests hit this path, one may read a sandbox flag set by the other, causing production receipts to validate against sandbox or vice versa. - **Impact**: Intermittent validation failures or sandbox receipts being accepted in production. ### SEC-17 | BUG | Index out of bounds in FCM response parsing - **File**: `internal/push/fcm.go:119` - **What**: `for i, result := range fcmResp.Results` iterates results and accesses `tokens[i]`. If FCM returns fewer results than tokens sent, this is safe, but if the response is malformed with more results than tokens, it panics. - **Impact**: Server panic on malformed FCM responses. ### SEC-18 | BUG | DeleteFile endpoint allows deleting any file without ownership check - **File**: `internal/handlers/upload_handler.go:78-91` - **What**: The `DELETE /api/uploads/` endpoint accepts a `url` field in the request body and passes it directly to `storageService.Delete`. There is no check that the authenticated user owns or has access to the resource associated with that file. - **Impact**: Any authenticated user can delete other users' uploaded files (images, documents, completion photos). ### SEC-19 | BUG | Unchecked type assertion throughout handlers - **File**: `internal/handlers/contractor_handler.go:28` (and 60+ other locations) - **What**: `c.Get(middleware.AuthUserKey).(*models.User)` is used without the comma-ok pattern across contractor_handler (7 instances), document_handler (10 instances), residence_handler (14 instances), task_handler (18 instances), and media_handler (3 instances). If the auth middleware is misconfigured or bypassed, this panics. - **Impact**: Server panic (500) on any request where the context value is not the expected type. ### SEC-20 | WARNING | Admin JWT accepted via query parameter - **File**: `internal/middleware/admin_auth.go:49-50` - **What**: `tokenString = c.QueryParam("token")` allows passing the admin JWT as a URL query parameter. URL parameters are logged by web servers, proxies, and browser history. - **Impact**: Admin tokens leaked into access logs, proxy logs, and referrer headers. A compromised log grants full admin access. ### SEC-21 | WARNING | Hardcoded debug secret key - **File**: `internal/config/config.go:339` - **What**: When `SECRET_KEY` is not set and `DEBUG=true`, the secret key defaults to `"change-me-in-production-secret-key-12345"`. If debug mode is accidentally enabled in production, all JWT signatures use this predictable key. - **Impact**: Trivially forgeable admin JWTs if debug mode leaks to production. ### SEC-22 | WARNING | XSS in admin email HTML template - **File**: `internal/admin/handlers/notification_handler.go:351-363` - **What**: `req.Subject` and `req.Body` are concatenated directly into HTML via string concatenation (`+ req.Subject +`), with no HTML escaping. If the admin enters `