Skip to content

console: FormPage's post-submit redirect uses the authored URL verbatim — undecided whether it is a console route or an arbitrary destination #4190

Description

@yinlianghui

Found by the window.location.assign / window.location.href = sweep that objectui#4181 asked for ("the set may be larger"). Filed unassigned, observation-class — see the reachability note before grading this.

What

apps/console/src/components/FormPage.tsx:574, the submitBehavior.kind === 'redirect' branch:

setTimeout(() => window.location.assign(behavior.url), delay);

behavior.url comes straight from the form's authored submitBehavior metadata and is used verbatim. location.assign bypasses React Router's basename, so on a console served under a mount (the framework CLI configures one for every embedded deployment) an authored console-relative path such as /objects/lead resolves to the ORIGIN root and leaves the SPA — the same class objectui#4181 fixed in SetupPage.

Why this is NOT simply "route it through withConsoleBase()"

That is the fix objectui#4181 applied to the three auth surfaces, and it does not transfer here. withConsoleBase() prefixes anything that does not begin with /_, so an absolute target would be mangled rather than fixed:

withConsoleBase('https://example.com/thanks')  ->  '/_console/https://example.com/thanks'

So the real question is upstream of the code: what is submitBehavior.url declared to mean?

  • If it is an arbitrary destination, today's behaviour is correct for the absolute case and the relative case is an authoring error the spec should reject or normalize.
  • If it is a console route, it needs the mount prefix — and the absolute case needs to be either rejected at publish time or explicitly allowed through a same-origin check.

Either way the fix wants a same-origin guard rather than an unconditional prefix, which is a contract decision, not a one-line patch. Worth noting the surface is reachable anonymously: mode: 'public' forms render at /f/:slug for visitors with no session, and an external thank-you page is a genuinely plausible authored intent there — which is exactly why guessing the semantics would be wrong.

Reachability — why finding and not a graded bug

It needs the intersection of two conditions, and neither is confirmed to exist today:

  • a console served under a mount (invisible on a bare / deployment, where prefixed and unprefixed spellings coincide — the same blind spot that hid objectui#4181); and
  • a form authored with a console-relative submitBehavior.url.

No such form was found in this repo's examples while sweeping, so nothing is known to hit it. Recording it rather than sitting on it, per filing discipline; the semantics question is the useful half and it survives regardless of whether any form triggers the bug today.

The rest of the sweep was clean

For the record, so the next reader does not repeat it — every other full-page navigation producer in apps/console is correct as written:

  • pages/auth/LoginPage.tsx (3 sites), pages/auth/RegisterPage.tsx (3), pages/auth/SetupPage.tsx (2) — all route through the shared console-mount helper as of objectui#4181.
  • pages/auth/OAuthConsentPage.tsx:109 and pages/auth/followAuthorize.ts:30,45 — OAuth redirect_uri / authorize targets, external and server-absolute by design. Prefixing these would break them.
  • pages/system/ApprovalsInboxPage.tsx:512 — a signed download URL, already prefixed with the SERVER base when relative and passed through when absolute. Storage URL, not an SPA route.

Blocked-by: objectstack-ai/objectstack#7496


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions