Remediate PEN-01 through PEN-07 (pentest round 4)

- PEN-01: fix extractBearerFromRequest to validate Bearer prefix
  using strings.SplitN + EqualFold; add TestExtractBearerFromRequest
- PEN-02: security headers confirmed present after redeploy (live
  probe 2026-03-15)
- PEN-03: accepted — Swagger UI self-hosting disproportionate to risk
- PEN-04: accepted — OpenAPI spec intentionally public
- PEN-05: accepted — gRPC port 9443 intentionally public
- PEN-06: remove RecordLoginFailure from REST TOTP-missing branch
  to match gRPC handler (DEF-08); add
  TestTOTPMissingDoesNotIncrementLockout
- PEN-07: accepted — per-account hard lockout covers the same threat
- Update AUDIT.md: all 7 PEN findings resolved (4 fixed, 3 accepted)

Security: PEN-01 removed a defence-in-depth gap where any 8+ char
Authorization value was accepted as a Bearer token. PEN-06 closed an
account-lockout-via-omission attack vector on TOTP-enrolled accounts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 23:14:47 -07:00
parent 1121b7d4fd
commit 5c242f8abb
3 changed files with 133 additions and 12 deletions

View File

@@ -23,12 +23,12 @@ Identified during the fourth-round penetration test on 2026-03-14 against the li
| ID | Severity | Finding | Status |
|----|----------|---------|--------|
| PEN-01 | Medium | `extractBearerFromRequest` does not validate "Bearer " prefix | **Fixed** — uses `strings.SplitN` + `strings.EqualFold` prefix validation, matching middleware implementation |
| PEN-02 | Medium | Security headers missing from live instance responses | **Open** (code/deployment discrepancy) |
| PEN-03 | Low | CSP `unsafe-inline` on `/docs` Swagger UI endpoint | **Open** |
| PEN-04 | Info | OpenAPI spec publicly accessible without authentication | **Open** |
| PEN-05 | Info | gRPC port 9443 publicly accessible | **Open** |
| PEN-06 | Low | REST login increments lockout counter for missing TOTP code | **Open** |
| PEN-07 | Info | Rate limiter is per-IP only, no per-account limiting | **Open** |
| PEN-02 | Medium | Security headers missing from live instance responses | **Fixed** — redeployed; all headers confirmed present on live instance 2026-03-15 |
| PEN-03 | Low | CSP `unsafe-inline` on `/docs` Swagger UI endpoint | **Accepted** — self-hosting Swagger UI (1.7 MB) to enable nonces adds complexity disproportionate to the risk; inline script is static, no user-controlled input |
| PEN-04 | Info | OpenAPI spec publicly accessible without authentication | **Accepted** — intentional; public access required for agents and external developers |
| PEN-05 | Info | gRPC port 9443 publicly accessible | **Accepted** — intentional; required for server-to-server access by external systems |
| PEN-06 | Low | REST login increments lockout counter for missing TOTP code | **Fixed**`RecordLoginFailure` removed from TOTP-missing branch; `TestTOTPMissingDoesNotIncrementLockout` added |
| PEN-07 | Info | Rate limiter is per-IP only, no per-account limiting | **Accepted** — per-account hard lockout (10 failures/15 min) already covers distributed brute-force; per-account rate limiting adds marginal benefit at this scale |
<details>
<summary>Finding descriptions (click to expand)</summary>
@@ -69,6 +69,9 @@ This is likely a code/deployment discrepancy — the deployed binary may predate
**Recommendation:** Redeploy the current source to the live instance and verify headers with `curl -I`.
**Fix:** Redeployed 2026-03-15. Live probe confirms all headers present on `/login`, `/v1/health`, and `/`:
`cache-control: no-store`, `content-security-policy`, `permissions-policy`, `referrer-policy`, `strict-transport-security: max-age=63072000; includeSubDomains`, `x-content-type-options: nosniff`, `x-frame-options: DENY`.
---
### PEN-03 — CSP `unsafe-inline` on `/docs` Swagger UI Endpoint (Low)
@@ -126,6 +129,8 @@ if acct.TOTPRequired {
**Recommendation:** Remove the `RecordLoginFailure` call from the TOTP-missing branch, matching the gRPC handler's behavior after the DEF-08 fix.
**Fix:** `RecordLoginFailure` removed from the TOTP-missing branch in `internal/server/server.go`. The branch now matches the gRPC handler exactly, including the rationale comment. `TestTOTPMissingDoesNotIncrementLockout` verifies the fix: it fully enrolls TOTP via the HTTP API, sets `LockoutThreshold=1`, issues a TOTP-missing login, and asserts the account is not locked.
---
### PEN-07 — Rate Limiter Is Per-IP Only, No Per-Account Limiting (Informational)
@@ -336,11 +341,9 @@ The following attacks were attempted against the live instance and failed, confi
**CRIT/DEF/SEC series:** All 24 findings remediated. No open items.
**PEN series (2026-03-14):** 1 of 7 findings remediated; 6 open (1 medium, 2 low, 3 informational). Unauthorized access was not achieved. Priority remediation items:
1. **PEN-02** (Medium): Redeploy current source to live instance and verify security headers
2. **PEN-06** (Low): Remove `RecordLoginFailure` from REST TOTP-missing branch
**PEN series (2026-03-14):** All 7 findings resolved — 4 fixed, 3 accepted by design. Unauthorized access was not achieved. No open items remain.
Next audit should focus on:
- Verifying PEN-01 through PEN-07 remediation
- Any new features added since 2026-03-14
- Any new features added since 2026-03-15
- Dependency updates and CVE review
- Re-evaluate PEN-03 if Swagger UI self-hosting becomes desirable