fix: enforce API request limits

Add a single platform-owned request-body policy (hono/body-limit) with
small, named limits for Better Auth and Core's grant-mutation endpoint, and
a new required maxBodyBytes field on the executable module route contract so
every module route makes a conscious no-body-or-bounded-body choice, capped
at a platform ceiling. Every oversized request gets one sanitized 413
contract and never reaches business logic, authorization, or a handler.
Also configure finite Node header/request/keep-alive timeouts, including the
non-obvious connectionsCheckingInterval needed for them to take effect
promptly, so a slow-header or slow-body connection cannot hold a socket
indefinitely.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
ekklesia
2026-07-26 12:29:24 -05:00
co-authored by Claude Sonnet 5
parent cafd513019
commit d3c6bd73d3
24 changed files with 1419 additions and 96 deletions
+26 -4
View File
@@ -8,7 +8,10 @@ surfaces.
Phase 3 is complete, and Phase 4A (Core identity foundation), Phase 4B (identity HTTP transport),
Phase 4C (Core authorization), Phase 5A (module authorization integration), Phase 5B (module HTTP
transport), and Phase 5C (module database access) have landed. The repository includes
transport), and Phase 5C (module database access) have landed. Phase 5D (public request perimeter
hardening against an independent security audit) is in progress; pass 1 of 5 has landed — see
below. **Phase 5D is not complete, and Phase 6 (Surface work) remains blocked until every audit
finding is resolved and a final re-audit passes.** The repository includes
public module contracts, independently versioned capabilities, static module manifests,
deterministic automatic discovery, compiled server loading, a staged capability registry,
dependency-ordered lifecycle with rollback, module-owned Drizzle table contracts, deterministic
@@ -32,9 +35,10 @@ in `@ekklesia/contracts`, and an explicit Better Auth construction boundary in C
Phase 4B adds identity HTTP transport: a minimal Hono-based `apps/api` composition root
(`pnpm api:start`) mounts Better Auth at `/api/auth/*` and exposes `GET /api/v1/principal` behind
Core's own Fetch-compatible identity runtime — Core still does not depend on Hono, and modules
still cannot reach any of this. Public email/password registration is intentional; every account
receives identical lowest-privilege baseline status and signup order never grants elevation. See
[API](docs/development/api.md) and
still cannot reach any of this. Public email/password registration is the intended eventual
product policy — every account receives identical lowest-privilege baseline status and signup
order never grants elevation — but is now **disabled by default** and requires an explicit opt-in
(Phase 5D pass 1, below). See [API](docs/development/api.md) and
[ADR 0011](docs/architecture/decisions/0011-identity-http-transport-and-public-enrollment.md).
**No email verification, password recovery, or Dashboard exists yet** — that, along with
production approval-provider composition, jobs, physical storage provisioning, surfaces, and
@@ -91,6 +95,24 @@ startup. See [API](docs/development/api.md#module-database-access),
[Module development](docs/module-development/README.md#database-access), and
[ADR 0016](docs/architecture/decisions/0016-module-database-access.md).
Phase 5D pass 1 of 5 hardens the public request perimeter against an independent security audit
of the Phase 5C checkpoint, without adding a Surface, a product module, or any new capability.
Better Auth's authentication rate limiter now resolves client identity from a server-owned
client-address boundary (`core/src/identity/client-address.ts`, wired in at the Node/API transport
boundary) — direct mode trusts only the real socket peer by default, and an explicit trusted-proxy
mode is required before any forwarded header is ever consulted, closing a rotating-header
rate-limit bypass. Public sign-up is now **disabled by default** and requires an explicit typed
opt-in (`EKKLESIA_PUBLIC_SIGNUP_ENABLED=true`). Every public body-consuming route — Better Auth,
Core's grant-mutation endpoint, and every module route (via a new, required `maxBodyBytes` field on
the executable route contract) — now has an explicit, platform-enforced byte ceiling with one
sanitized `413` contract. The Node HTTP server now has finite header/request timeouts. See
[API](docs/development/api.md), [Module development](docs/module-development/README.md#http-routes),
and [ADR 0017](docs/architecture/decisions/0017-public-request-perimeter-hardening.md). **This pass
does not add distributed rate limiting, durable public-signup abuse control, or any deployment/TLS
guarantee, and it does not complete Phase 5D** — passes 2–5 (identity/database transport hardening,
authorization integrity, module/runtime/migration correctness, and deployment/supply-chain closure
plus a final independent re-audit) remain outstanding before Phase 6 (Surface work) may begin.
## Quick start
Prerequisites: Node.js 24 LTS, pnpm 11.12, and Docker with Compose.