Skip to content

Commit 901ff41

Browse files
committed
Reject whitespace-only resolved identity, not just empty strings (CL-6286)
ResolvedCallerSchema used "string >= 1" -- a LENGTH constraint, so " " (length 1) passed it and got seated as a "valid" principal/tenant, just like the empty-string exploit in a different costume. Require at least one non-whitespace character (type("string").narrow(s => s.trim().length > 0)) instead, with a ctx.mustBe() message so the rejection reads clearly in logs.
1 parent 22573d3 commit 901ff41

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

‎src/routes/deps.ts‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,27 @@ export type CallerResolver = (
4141
c: Context<TenantEnv>,
4242
) => ResolvedCaller | null | Promise<ResolvedCaller | null>;
4343

44+
/**
45+
* `"string >= 1"` is a LENGTH constraint, not a content one — `" "` has
46+
* length 1 and would pass it, seating a whitespace-only scope exactly like
47+
* the empty-string case this schema exists to reject. Require at least one
48+
* non-whitespace character instead.
49+
*/
50+
const NonBlankId = type("string").narrow(
51+
(s, ctx) => s.trim().length > 0 || ctx.mustBe("non-blank (not just whitespace)"),
52+
);
53+
4454
/**
4555
* The one boundary where a host hands this package an identity, so it is
4656
* parsed like any other trust boundary (AGENTS.md invariant 4) rather than
4757
* trusted as an opaque TS shape. A resolver returning `{tenantId: "",
48-
* principalId: ""}` (or anything not matching this shape) is rejected here,
49-
* never seated as a "valid" empty-string scope.
58+
* principalId: ""}` or `{tenantId: " ", principalId: " "}` (or anything not
59+
* matching this shape) is rejected here, never seated as a "valid"
60+
* empty/blank scope.
5061
*/
5162
const ResolvedCallerSchema = type({
52-
tenantId: "string >= 1",
53-
principalId: "string >= 1",
63+
tenantId: NonBlankId,
64+
principalId: NonBlankId,
5465
});
5566

5667
export type RouteDeps = {

0 commit comments

Comments
 (0)