170 lines
18 KiB
Markdown
170 lines
18 KiB
Markdown
---
|
|
phase: 06-http-routing-auth-groups-and-rate-limiting
|
|
plan: 11
|
|
type: execute
|
|
wave: 7
|
|
depends_on: ["06-07", "06-08", "06-09", "06-10"]
|
|
files_modified:
|
|
- .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
autonomous: true
|
|
gap_closure: true
|
|
requirements: [HTTP-03, HTTP-04, HTTP-05, HTTP-06, HTTP-07, HTTP-08, HTTP-09]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "The security review no longer claims zero open threats until all four corrective plans and both repositories' complete `go test ./... -count=1 -race -short` gates pass"
|
|
- "T-06-24 records the anonymous key as exactly `inline:domainless|<ClientIP>` and explicitly excludes the throttle parameter, `r.Host`, `Forwarded` host, and `X-Forwarded-Host` from bucket selection"
|
|
- "T-06-23 through T-06-27 map atomic admission, domainless inline keys, transition-address SSRF rejection, clean partial-write panic recovery, and exact InvScope bytes to named passing tests"
|
|
- "T-06-24 cites the named Plan 06-07 Host-rotation, cross-inline-parameter shared-budget, and authenticated `u:<id>` isolation regressions"
|
|
- "The review's verdict, scope, totals, accepted-risk count, and audit trail agree with the post-fix code and evidence"
|
|
- "Any failed corrective test leaves the review open/blocked rather than documenting a false verified state"
|
|
artifacts:
|
|
- path: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
provides: "Post-gap Phase 6 ASVS L1 threat map and evidence-backed verdict"
|
|
key_links:
|
|
- from: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
to: summercms.go/surf/limiter_test.go
|
|
via: "T-06-23/T-06-24 cite the coordinated concurrency plus the named `TestFixedWindowLimiterInlineThrottleKeys` Host-rotation, cross-inline-parameter shared-budget, and authenticated-principal isolation cases"
|
|
pattern: "TestFixedWindowLimiterInlineThrottleKeys"
|
|
- from: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
to: summercms.go/fetchguard/ip_test.go
|
|
via: "T-06-25 cites NAT64/6to4 embedded-private and public-control cases"
|
|
pattern: "T-06-25"
|
|
- from: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
to: summercms.go/surf/router_test.go
|
|
via: "T-06-26 cites raw and house partial-write panic regressions"
|
|
pattern: "T-06-26"
|
|
- from: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
to: fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope_test.go
|
|
via: "T-06-27 cites exact no-newline 401/403 byte assertions"
|
|
pattern: "T-06-27"
|
|
---
|
|
|
|
<objective>
|
|
Refresh the Phase 6 ASVS L1 security review only after all corrective code and tests are green, replacing the stale zero-open conclusion with a complete post-gap threat map and auditable evidence.
|
|
|
|
Purpose: the review is itself a required phase artifact. Its verdict must describe the current code, not the pre-review snapshot that missed four security/contract failures.
|
|
Output: an updated `06-SECURITY-REVIEW.md` covering Plans 06-01 through 06-10 plus the Plan 06-11 review refresh, with all five new threats accurately closed or the phase explicitly blocked.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/jin/.codex/get-shit-done/workflows/execute-plan.md
|
|
@/home/jin/.codex/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/REQUIREMENTS.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-CONTEXT.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-VERIFICATION.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-REVIEW.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-07-SUMMARY.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-08-SUMMARY.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-09-SUMMARY.md
|
|
@.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-10-SUMMARY.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Re-run Phase 6 security gates and publish the post-gap threat verdict</name>
|
|
<files>.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md</files>
|
|
<read_first>
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md (current stale header, threat register, findings, accepts, and audit trail; preserve all still-valid evidence)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-VERIFICATION.md (authoritative four code gaps plus stale-review gap)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-REVIEW.md (CR-01 through CR-04 and WR-11 source evidence)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-07-PLAN.md and 06-07-SUMMARY.md (T-06-23/T-06-24 and actual test names/results)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-08-PLAN.md and 06-08-SUMMARY.md (T-06-25 and actual transition tests/results)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-09-PLAN.md and 06-09-SUMMARY.md (T-06-26 and actual recovery tests/results)
|
|
.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-10-PLAN.md and 06-10-SUMMARY.md (T-06-27 and actual byte-contract tests/results)
|
|
surf/limiter.go, surf/limiter_store.go, surf/limiter_test.go (executed atomic admission and stable-key code/evidence)
|
|
fetchguard/ip.go, fetchguard/ip_test.go, fetchguard/fetch_test.go (executed transition classifier and dial-time evidence)
|
|
surf/router.go, surf/router_test.go (executed buffer/discard recovery and partial-write evidence)
|
|
../fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope.go and token_scope_test.go (executed no-newline writer and exact-byte evidence)
|
|
</read_first>
|
|
<action>
|
|
Before editing the review, run the repository-level verification commands below. The authoritative suite gates are exactly `go test ./... -count=1 -race -short` from summercms.go and the same command from sibling fonoteka.go; package-targeted race runs or full suites without `-race` are not substitutes. If any command fails, do not set `status: verified`, do not set `threats_open: 0`, and do not add a zero-open audit row; stop and report the failing threat/test as blocking. High-severity T-06-23 through T-06-26 may not be accepted or deferred.
|
|
|
|
After all gates pass, update `06-SECURITY-REVIEW.md` frontmatter date/status/threat count and scope so it explicitly covers Plans 06-01 through 06-10 and the Plan 06-11 review refresh. Preserve every existing T-06-01..18, T-06-21, T-06-22, and T-06-SC row and its disposition unless the new code invalidates the old evidence; do not erase accepted-risk rationales or prior audit-trail rows.
|
|
|
|
Add five mitigate rows and matching detailed `Findings by Threat` sections using the actual executed test names from the four summaries: T-06-23 for atomic threshold check+increment and coordinated Max=1 evidence; T-06-24 for the server-controlled `inline:domainless|<ClientIP>` key; T-06-25 for RFC 6052 well-known/local-use NAT64 plus 6to4 embedded loopback/RFC1918/metadata rejection, public controls, and dialControl proof; T-06-26 for buffer/discard recovery with both raw and house partial-write-then-panic exact response assertions; T-06-27 for `wire.WriteJSON` and raw-byte 401/403 assertions with no trimming. For T-06-24, state explicitly that the anonymous key excludes the throttle `param`, `r.Host`, the `Forwarded` host parameter, and `X-Forwarded-Host`. Cite the exact executed names recorded by Plan 06-07's summary/source for all three inline-key regressions under `TestFixedWindowLimiterInlineThrottleKeys`: the Host-rotation subtest, the same-IP shared-budget subtest spanning different inline throttle parameters, and the authenticated-principal subtest proving independent `u:<id>` buckets. Copy the complete slash-qualified names from the executed test source/summary rather than describing unnamed cases. Do not reduce this to a Host-rotation citation or claim that a throttle parameter selects any portion of the anonymous key. Cite concrete source identifiers and named tests, not only plan numbers.
|
|
|
|
Update the trust-boundary table for concurrent limiter admission, IPv6 transition decoding, buffered response commit, and token-scope serialization. Update summary prose, accepted-risk count, closed/open totals, and Security Audit Trail consistently. With the existing 21 reviewed IDs plus five new mitigations, the successful review total is 26 threats, 26 closed, zero open; T-06-SC remains one of the 26 and no new accepted risk is introduced. Do not change `06-VERIFICATION.md`; re-verification remains the verifier's next step.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && go test ./... -count=1 -race -short && go vet ./... && cd ../fonoteka.go && go test ./... -count=1 -race -short && go vet ./... && cd ../summercms.go && test "$(awk -F'|' '/^\| T-06-(23|24|25|26|27) / {c++} END {print c+0}' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md)" -eq 5 && rg -n '26 \| 26 \| 0|threats_open: 0|Plans 06-01 through 06-10' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && rg -n 'inline:domainless\|<ClientIP>' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && rg -n 'TestFixedWindowLimiterInlineThrottleKeys/.+(Host|host)' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && rg -n 'TestFixedWindowLimiterInlineThrottleKeys/.+(param|policy)' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && rg -n 'TestFixedWindowLimiterInlineThrottleKeys/.+(principal|authenticated|user)' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && rg -n 'u:<id>' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md && ! rg -n 'inline:<param>\|<ClientIP>|param\+ClientIP|anonymous (bucket|key).*(uses|includes|contains|combines).*(throttle )?param' .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- The review update occurs after all four plan summaries exist and `go test ./... -count=1 -race -short` plus `go vet ./...` exit 0 in both summercms.go and fonoteka.go.
|
|
- The Threat Register contains exactly one row each for T-06-23, T-06-24, T-06-25, T-06-26, and T-06-27, all disposition `mitigate`, each naming executed source/test evidence.
|
|
- Findings by Threat contains substantive sections for all five new IDs: coordinated concurrency; exact `inline:domainless|<ClientIP>` construction; named Host-rotation, cross-inline-parameter shared-budget, and authenticated `u:<id>` isolation regressions; all three transition prefixes; both partial-write route kinds; and raw exact 401/403 bytes.
|
|
- T-06-24 says the anonymous signature excludes throttle `param`, `r.Host`, `Forwarded` host, and `X-Forwarded-Host`; the source/verification grep rejects stale `inline:<param>|<ClientIP>`, `param+ClientIP`, or equivalent parameter-selected anonymous-key claims.
|
|
- Frontmatter, summary, accepted-risk log, threat totals, and the newest audit-trail row agree on 26 total, 26 closed, zero open only when every gate passed.
|
|
- Every earlier threat row and audit-trail history remains present; no high-severity gap is silently accepted, deferred, or omitted.
|
|
- `06-VERIFICATION.md` is not edited by this plan.
|
|
</acceptance_criteria>
|
|
<done>The Phase 6 security review truthfully reflects the corrected code and supplies auditable, named test evidence for every previously unresolved security/contract gap.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| implementation evidence -> security verdict | A stale or optimistic review can falsely release security-load-bearing primitives to dependent phases |
|
|
| test gates -> documentation state | Zero-open status is allowed only when the exact adversarial tests and both repository suites pass |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|-------------|-----------------|
|
|
| T-06-23 | Denial of Service | concurrent limiter admission | mitigate | Require atomic Attempt implementation and coordinated Max=1 passing evidence before review closure |
|
|
| T-06-24 | Denial of Service | anonymous inline key selection | mitigate | Require exact `inline:domainless|<ClientIP>` key, exclude throttle param and all request/forwarded Host inputs, and cite named Host-rotation, cross-inline-parameter shared-budget, and authenticated `u:<id>` isolation regressions |
|
|
| T-06-25 | Elevation of Privilege / Information Disclosure | transition-address SSRF classification | mitigate | Require NAT64 /96, local-use NAT64 /48, and 6to4 embedded-private plus dialControl tests |
|
|
| T-06-26 | Information Disclosure | raw/house panic recovery | mitigate | Require partial-write status/header/body discard tests for both route kinds |
|
|
| T-06-27 | Tampering | personal-token denial serialization | mitigate | Require `wire.WriteJSON` and exact untrimmed 401/403 byte comparisons |
|
|
| T-06-SC | Tampering | package supply chain | accept | Gap plans add no dependencies; retain the existing Phase 6 package-legitimacy disposition |
|
|
</threat_model>
|
|
|
|
<source_coverage_audit>
|
|
| Source | ID | Feature / Requirement | Plan | Status | Notes |
|
|
|--------|----|-----------------------|------|--------|-------|
|
|
| GOAL | Phase 6 | Secure shared auth groups, 1:1 rate limiting, raw OAuth boundary, and SSRF guard | 06-07..06-11 | COVERED | Four defects fixed in parallel; review refresh follows all code/test plans |
|
|
| REQ | HTTP-03 | Mutually exclusive groups share handlers | 06-11 | COVERED (existing + regression gate) | Implemented by 06-01/06-05; full suite confirms no regression |
|
|
| REQ | HTTP-04 | Named/inline rate limits and stacking | 06-07, 06-11 | COVERED | Atomic admission and exact `inline:domainless|<ClientIP>` anonymous keys close the current blockers without trusting param or Host input |
|
|
| REQ | HTTP-05 | Unified guard registry/current-user accessor | 06-10, 06-11 | COVERED | Existing registry retained; exact personal-token denial contract is verified |
|
|
| REQ | HTTP-06 | Response conventions and raw exemption | 06-09, 06-10, 06-11 | COVERED | Clean partial-write recovery and no-newline TokenScope bytes |
|
|
| REQ | HTTP-07 | Guarded outbound fetch | 06-08, 06-11 | COVERED | Transition addresses receive embedded IPv4 classification at dial time |
|
|
| REQ | HTTP-08 | OpenAPI/type generation | 06-11 | COVERED (existing + regression gate) | Implemented by 06-03; no authoritative current gap requests replanning |
|
|
| REQ | HTTP-09 | CORS/body limits | 06-11 | COVERED (existing + regression gate) | Implemented by 06-03; no authoritative current gap requests replanning |
|
|
| RESEARCH | Fixed-window semantics | First-hit fixed window and PHP headers/body | 06-07 | COVERED | Atomic API preserves the established sequential contract |
|
|
| RESEARCH | SSRF dial-time guard | Actual connected address is classified | 06-08 | COVERED | Transition extraction feeds the existing dial-time classifier |
|
|
| CONTEXT | D-01..D-05 | Five buckets, fixed-window parity, stdlib store, trusted ClientIP, parameterized names | 06-07 | COVERED | No bucket limit/key ownership or middleware syntax is reduced |
|
|
| CONTEXT | D-06..D-10 | Guard registry, real token guard, exact InvScope bodies, no OAuth stub, unchanged JWT | 06-10 | COVERED | D-08 exact bytes repaired; remaining decisions preserved |
|
|
| CONTEXT | D-11..D-14 | AllowHosts/PublicOnly, dial-time rejection, typed failures, caps/timeouts | 06-08 | COVERED | Transition forms added without changing caller scope or limits |
|
|
| CONTEXT | D-15..D-18 | Group subsets, raw bare recovery, response conventions/OpenAPI, CORS/body limits | 06-09, 06-11 | COVERED | D-16 is upheld after partial writes; unrelated existing outputs regression-tested |
|
|
| CONTEXT | Deferred Ideas | Later route handlers/call sites | — | EXCLUDED | Explicitly out of Phase 6 and absent from authoritative `gaps:` |
|
|
| REVIEW | Warnings outside verifier gaps | WR-01..WR-10 except promoted WR-11 | — | EXCLUDED | Gap-closure mode plans only authoritative `06-VERIFICATION.md` gaps; these remain review backlog, not silently claimed fixed |
|
|
</source_coverage_audit>
|
|
|
|
<verification>
|
|
Run `go test ./... -count=1 -race -short` and `go vet ./...` in both repositories before documentation can claim verified/zero-open. Validate five new unique threat rows, matching detailed findings, consistent 26/26/0 totals, preserved prior evidence, and a scope statement covering the corrective plans. Assert positively that T-06-24 names `inline:domainless|<ClientIP>` and the three Plan 06-07 inline-key regressions, and fail if the review contains `inline:<param>|<ClientIP>`, `param+ClientIP`, or an equivalent parameter-selected anonymous-key claim. If any command or assertion fails, leave the verdict open and stop.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- The stale Phase 6 security verdict is replaced by evidence matching the post-gap code.
|
|
- T-06-23 through T-06-27 are each closed by concrete named tests, never by assertion alone.
|
|
- T-06-24 documents only `inline:domainless|<ClientIP>`, explicitly excludes throttle param and all request/forwarded Host input, and cites the named Host-rotation, cross-inline-parameter shared-budget, and authenticated `u:<id>` isolation tests.
|
|
- The successful audit is internally consistent at 26 total / 26 closed / 0 open with no new accepted risk.
|
|
- A failed full-repository `-race` suite, vet gate, or anonymous-key source assertion in either repository cannot produce a verified/zero-open document.
|
|
- All four source categories are fully covered without planning deferred items or non-authoritative warnings.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-11-SUMMARY.md` when done.
|
|
</output>
|