fix: harden sign-in classification + align take-over messaging

Merged
TO
3mo ago
+118-10

What

Addresses the review findings on our browser sign-in code surfaced in the production-deploy PR (#3521). These touch code merged via #3520; fixes go to main (not the deploy PR).

  • URL as untrusted data (browser-login-classifier): the browser's current URL is now passed to the classification prompt labeled + delimited as untrusted, so page-path text can't steer the outcome. (Query/fragment were already stripped by safeOriginAndPath.)
  • Tighter 2FA-method classification: a device approval, push notification, or email/SMS link is classified as other instead of over-matching a passkey — so take-over guidance matches the page.
  • Consistent take-over messaging (ConnectVendorLoginFlow): the toast and the panel now derive from the same decision, so they can't contradict (e.g. an "enter your code" toast over a "finish sign-in" panel).
  • Tests for classifyLoginOutcome: each outcome, throw → unknown, URL passed as untrusted with secrets stripped, and content-only when no URL is available.

Not included (deliberately)

Two other findings on #3521 are the training team's (portal/complete-training), not this feature — left for them.

Notes

The two classifier changes are prompt/LLM hardening (behavior isn't 100% guaranteed), but they're low-risk and improve correctness; the take-over flow stays interactive, so it degrades gracefully.

Tests

210 API tests (29 suites) + 96 app browser-automations tests green; both apps typecheck clean.


Summary by cubic

Hardens browser sign-in classification and makes take-over messaging consistent. Blocks URL-steered misclassification, delimiter injection, and conflicting toast/panel guidance.

  • Bug Fixes
    • Treat the current URL as untrusted, delimited data in the prompt; strip query/fragment via safeOriginAndPath, ignore non-http(s) schemes, and XML-escape the value.
    • Tighten 2FA detection: device approval, push, or email/SMS link → other; only explicit passkey prompts → passkey/passkey_only.
    • Align ConnectVendorLoginFlow toast and panel to the same decision (2FA vs finish) to avoid contradictions.
    • Add tests for classifyLoginOutcome: each outcome, errors → unknown, content-only with no URL, sanitized URL stays inside <current_url>, and non-http(s) URLs are dropped.