Skip to content

fix(levelcode): sign-in next refuses the /ai/ endpoints in every spelling the router answers - #456

Merged
ndemianc merged 1 commit into
developfrom
fix/levelcode-next-endpoint-aliases
Oct 18, 2026
Merged

ndemianc merged 1 commit into
developfrom
fix/levelcode-next-endpoint-aliases

Conversation

@ndemianc

Copy link
Copy Markdown
Member

What

A follow-up to #454 (merged). After a sign-in, next must name a page of the account site. It already refused the server's own /ai/ endpoints, but only in their exact spelling. Rails also answers /ai/csrf.json and /ai/csrf/, and /ai/%63srf (an encoded c) passed too, so a sign-in could land on the CSRF token's JSON instead of a page.

The reviewer of the account-site half (systemu-net/onetime#100, comment 4308831990) asked for the same exclusion here.

The rule

The first segment after /ai/ is read the way the router reads a name: lower case, up to the first character that isn't a letter, digit or underscore (so csrf.json and csrf;x read as csrf). It is checked both as written and percent-decoded. It is refused if it is one of the ai scope's routes in config/routes.rb:

  • auth
  • authorize_editor
  • checkout
  • billing
  • signout
  • csrf

A page whose name only starts like one (/ai/csrfx), or that has an endpoint's name further down the path (/ai/docs/auth), is still accepted.

The account site's isServerName is the same rule. Both validators were run over the same 40,000 generated values: 4,227 accepted by both, no disagreements.

Verified

  • spec/requests/levelcode/web_spec.rb and session_cookie_spec.rb: 114 examples, 0 failures. Eleven more refused spellings are in the table, plus a test that a look-alike name still lands on its page.
  • rubocop is clean on the changed files.

Note: locally, spec/requests/api/levelcode/v1/admin_spec.rb:42 fails (auth_failures is 3, expected 1). That is unrelated to this change; it fails the same way on develop, before and after #454. The local test database holds two failed-sign-in rows from 21:30:59 UTC that no spec left behind; I checked that the sign-in specs leave no rows. CI starts from a clean database.

🤖 Generated with Claude Code

…lling the router answers

From the review of the account-site half (onetime #100, comment 4308831990), which asked for the
same exclusion here: safe_next refused /ai/auth/… and /ai/csrf as written, but Rails also answers
/ai/csrf.json and /ai/csrf/, and /ai/%63srf named it too.

The first segment after /ai/ is read as the router reads a name (lower case, up to the first
character that is not a letter, digit or underscore), as written and percent-decoded, and refused
when it is one of the "ai" scope's routes: auth, authorize_editor, checkout, billing, signout, csrf
(NEXT_SERVER_NAMES). The SPA's isServerName is the same rule; the two validators agree on 40,000
generated values.

Specs: eleven more refused spellings, and pages whose name only starts like an endpoint's or has
one further down still land.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused validation change matches the stated rule, has regression coverage, and has no identified blocking issues.

No open issues 🎉

What changed in this PR

Hardens post-sign-in next validation so account-site redirects reject alternate spellings of server endpoints.

Changes:

  • Checks endpoint names both as written and percent-decoded.
  • Adds regression coverage for rejected variants and accepted look-alike page paths.
File Description
spec/​requests/​levelcode/​web_spec.rb Tests endpoint variants and valid page paths.
app/​controllers/​levelcode/​web_controller.rb Rejects server endpoint names during redirect validation.

Review effort: Balanced

@ndemianc
ndemianc merged commit 7e9669a into develop Oct 18, 2026
4 checks passed
@ndemianc
ndemianc deleted the fix/levelcode-next-endpoint-aliases branch October 18, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants