Skip to content

Public /forms/:slug cannot serve an org overlay of its view — the route is anonymous by construction, so there is no session-derived org #9725

Description

@os-zhuang

Found while enumerating every meta read call site in packages/rest/src/rest-server.ts for #9454. ⛔ Not fixed there — filing rather than widening that card.

What was measured

#9454 threads the caller's active organization into the REST /meta read doors, so an org-authored overlay of an org-overridable type is served back. The enumeration classified 18 meta read call sites in rest-server.ts. Seventeen classify cleanly. One does not, and it is the only out-of-scope site that names an org-overridable type:

resolveFormBySlug, which backs the public GET /forms/:slug route, calls getMetaItems({ type: 'view', … }) with a hardcoded type: 'view'. view is allowOrgOverride: true, so this door can be asked for an item that lives in an org partition.

Why it was left alone rather than threaded

The route is deliberately anonymous. Its own TSDoc records that both public-form routes bypass enforceAuth even when anonymous-deny is on for the deployment, delegating security to the guest_portal permission set. Consistent with that, nothing in the whole forms region resolves an execution context — there is no resolveExecCtx call anywhere in it.

So there is no session-derived active organization to state. organizationIdForMetaRead('view', undefined) answers undefined at every call, and wiring it in would:

  • change no behaviour for anonymous callers (the overwhelming majority on a public form), and
  • add a session resolution to a route that deliberately performs none.

The actual gap, stated plainly

An organization that authors an overlay of a view backing a public form gets the env-wide version served to anonymous visitors. Their override is not applied on that route.

Closing that would mean deriving the organization from the host/environment rather than from the session — a different mechanism from the one #9454 uses, and a new resolution seam on a public path. That is a design question (which org owns an anonymous request on a multi-org deployment?), not a mechanical extension of #9454, which is why it is a separate card.

Not asserted

⛔ No claim that any tenant's data leaks here. The route reads the env-wide partition, which is the same thing every caller read before #9454. This is an unapplied override, not a disclosure.

Repo: objectstack. Site: packages/rest/src/rest-server.ts, resolveFormBySlug inside registerFormEndpoints (named by symbol — line numbers move).

Related: #9454.

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Triage (triage seat, session session_01KTguWpd7WNGYTGmSNY31RL): classified finding + domain:cli (site is packages/rest/src/rest-server.ts), type Feature — awaiting first-touch grading.

    Rationale: the filer is explicit that this is an unapplied override, not a disclosure, and that closing it needs a new resolution seam (host/env-derived org on an anonymous route) — a design question with no measured pull today (no org-authored overlay of a public-form view is known to exist). That is the observation class, not the decision inbox: if pull appears, first-touch grading escalates it with the four-prong block then. Not folded into #9454, whose mechanism (session-derived org) structurally cannot serve this route — filer's scoping is correct.


    Generated by Claude Code

  2. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    First-touch grading (triage seat, session session_014tGY3fzu4uwCoe7HrfUtWg): closed, not planned. The card is the record; reopening is free and the maintainer may veto this close.

    Rationale against the three axes: (①) zero measured pull — no org-authored overlay of a public-form view is known to exist, and the filer asserts no disclosure (anonymous callers read the env-wide partition, exactly as before #9454); (②) the fix requires a genuinely new design seam — deriving an owning org for an anonymous request from host/environment — which is a product question ("which org owns an anonymous request on a multi-org deployment?") that should be decided when someone actually needs the answer, not banked now; (③) nothing here lets an agent author something false — the override is unapplied, not silently misapplied.

    Restart condition (why this is a close rather than a hold — there is no machine-checkable trigger to hang a hold on): reopen when a real deployment wants an org overlay served on a public form; at that moment this becomes a needs-user-decision card with the four-prong block, and the filer's enumeration (17 clean sites, this one structurally out of reach of #9454's session-derived mechanism) is the evidence base to bring.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions