fix(review): harden the E2E-gap fixes after security/regression review
Addresses findings from an independent review of the gap-closing commits: - R1 (regression): add #[serde(default)] to HttpDispatchPayload.method so async-HTTP outbox rows enqueued before the field existed still decode after upgrade instead of dead-lettering on "missing field `method`". Adds a regression test for the missing-key path. - method case: uppercase ctx.request.method at the orchestrator boundary so it honors its documented "uppercased" contract for extension verbs. Route matching is already case-insensitive, so matching is unaffected. - CLI hardening: percent-encode free-form path segments (app slug, topic name, ids, secret name) in the reqwest client so a value containing `/ ? #` can't break out of its URL segment. Adds a `seg()` helper + unit test and applies it uniformly across all path-interpolating methods (new and pre-existing). - S1 (docs): correct the users::email_available enumeration framing — it adds no new vector vs. create's uniqueness error, but is cheaper and unthrottled; there is no built-in throttle/CAPTCHA primitive, so the honest mitigation is a kv-based counter. Updated SDK doc-comments, trait docs, and stdlib-reference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -520,9 +520,17 @@ impl UsersService for UsersServiceImpl {
|
||||
// Gated like `create` (the registration write path) so the probe
|
||||
// is available exactly where self-serve registration is — and,
|
||||
// crucially, WITHOUT find_by_email's anonymous-principal rejection.
|
||||
// It returns only a boolean, so it leaks no more than `create`'s
|
||||
// own uniqueness error already does (F-S-003: enumeration risk is
|
||||
// bounded to "exists / doesn't").
|
||||
//
|
||||
// SECURITY (F-S-003, enumeration): a single probe reveals only
|
||||
// "exists / doesn't" — the same bit a register form leaks via its
|
||||
// "email already taken" path. But unlike `create`, this probe has
|
||||
// no Argon2 cost and no side effect (a `create` miss writes a junk
|
||||
// row), so it is a *cheaper, quieter* enumeration oracle when a
|
||||
// script exposes it on an anonymous public route. It is NOT rate
|
||||
// limited here, and there is no built-in per-route throttle/CAPTCHA
|
||||
// primitive. Scripts that put this behind a public endpoint and
|
||||
// care about enumeration must add their own `kv`-based counter.
|
||||
// See docs/stdlib-reference.md.
|
||||
self.require(cx.principal.as_ref(), Capability::AppUsersWrite(cx.app_id))
|
||||
.await?;
|
||||
let normalized = validate_email(email)?;
|
||||
|
||||
Reference in New Issue
Block a user