Sloth-ninja makes Clio account linking stop guessing

A small security correction makes the Clio connection reject unsafe callback addresses in production.

securityintegration

Clio, a legal practice management platform, uses a return address when someone links an account. Sloth-ninja has tightened that step so the system will not quietly derive or accept a fallback address in a live deployment.

That matters because a wrong return address can send an account-linking flow to the wrong place, creating an opening for redirect or account-linking attacks. The fork now expects the public address to be set deliberately, with checks and configuration guidance to catch mistakes before launch.

The change is narrow, but it is the kind of guardrail that separates a demo integration from one fit for real client operations.

So what Teams considering the Clio integration should inspect this change and confirm their own canonical public address before adopting it.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from Sloth-ninja/JessicaOSS, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
6fc6afa6 Harden OAuth callback base: fail closed in production sloth-ninja 2026-08-04 ↗ GitHub
commit body
Incident 03/08/2026: the deployed backend minted Clio authorize URLs with
redirect_uri=http://127.0.0.1:3001/... because neither API_PUBLIC_URL nor
BACKEND_URL was set on Fly, so clioBackendBaseUrl() fell through to its dev
literal. A pilot solicitor's consent succeeded at Clio then bounced to
127.0.0.1 (ERR_CONNECTION_REFUSED). Fixed operationally by setting
API_PUBLIC_URL; this makes the failure loud and early instead of silent.

- clio/config.ts: new productionCallbackBaseMissing() - in NODE_ENV=production
  when the resolved base is the 127.0.0.1 fallback, clioConfigured() returns
  false (same state as missing credentials), so the start route returns the
  fixed "not configured" error and never mints a localhost redirect. A redacted
  safeErrorLog fires once per boot naming API_PUBLIC_URL. Dev/test unchanged.
- MCP checked: the interactive authorize redirect derives from the Host header
  (routes/user.ts backendPublicUrl) - different fallback class, unaffected on
  Fly, left unchanged. The refresh-path helper mcpOAuthCallbackUrl() shares the
  localhost fallback but is covered by API_PUBLIC_URL being required in prod.
- .env.example + CLAUDE.md env registry: API_PUBLIC_URL/BACKEND_URL documented
  as REQUIRED in production for OAuth callback flows (Clio + MCP).
- DURABLE_LESSONS: env-derived callback bases degrade silently; guard fails
  closed; OAuth deploy verification needs a real round-trip from a non-dev
  machine. Includes the debugging signature.
- Tests: 4 guard cases (prod+fallback -> not configured/no URL; prod+base ->
  normal; dev+fallback -> unchanged). Backend vitest 604/604, tsc + prettier
  clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
95778692 Merge pull request #68 from Sloth-ninja/oauth-base-hardening Ezana.H 2026-08-04 ↗ GitHub
Harden OAuth callback base: fail closed in production

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-1004.md from inside the repo you want the changes in.

⬇ Download capture-thread-1004.md