Skip to content

fix(flowsafe): contain malformed-path URIError in P6 routers (pre-auth)#33

Merged
gcharang merged 1 commit into
devfrom
fix/pre-auth-decode-hardening
Jul 18, 2026
Merged

fix(flowsafe): contain malformed-path URIError in P6 routers (pre-auth)#33
gcharang merged 1 commit into
devfrom
fix/pre-auth-decode-hardening

Conversation

@gcharang

Copy link
Copy Markdown
Contributor

Closes a confirmed pre-auth defect discovered during Track E's review (post-program hardening).

The bug

The P6 ingestion routers (signals/router.ts, goals/objective-routes.ts, schedules/router.ts) decoded the threadId/schedule-id path segment with bare decodeURIComponent before authentication and outside their try block, and createFlowsafeWorker.fetch wrapped the router calls in no try/catch. So an unauthenticated request with malformed percent-encoding — POST /api/threads/%/message, PUT /api/threads/%/goal, GET /api/schedules/% — threw a URIError out of fetch() as a per-request 500 with a logged exception. Bounded (per-request, no data leak, no amplification, no isolate crash), but a real pre-auth exposure. Track E's own webhook router already did this correctly with a local safeDecodeSegment.

The fix

  • Shared helper host-kit/route-path.tssafeDecodeSegment (zero-dependency leaf; returns undefined on malformed encoding). Internal: imported directly by the routers, not barrel-exported, so no new public API and the changeset stays a patch.
  • Adopted in the three pre-auth routers → malformed encoding is route-absent (null), byte-identical to a non-matching path (no audit, no existence oracle — the null path is pre-resolve).
  • Whole-class sweep: the background-tasks read route (background-tasks/routes.ts, post-auth, DO-mounted) adopts it too → malformed taskId returns its no-oracle 404 instead of throwing. Deduped the local copy from the Track E webhook router.
  • Defense-in-depth: a top-level try/catch in createFlowsafeWorker.fetch contains any handler throw (present or future) as a generic 500 — no error.message leaked to the client, logged as worker-fetch-error.

Behavior-preserving for all valid paths (the removed ?? '' fallback was dead — the path-shape length guard already guarantees the segment exists; the schedules list route still yields id=undefined and composes).

Verification

  • Gate: lint + typecheck + 1786 tests (94 files, +8) + build + spike:verify — green, run independently (3 gate runs across the change's evolution).
  • 8 new regression tests: the helper unit (valid decode, lone %, %zz, a%, undefined), one malformed-% test per router (route-absent / 404, asserting no-audit / no-write / no-throw), and the worker backstop (an injected throwing router → generic 500 + worker-fetch-error log).
  • Review lane: CLEAN. Two LOW findings resolved before commit — the helper docstring reworded to the accurate two-layer story (primary source-level defense + worker try/catch as defense-in-depth), and the helper kept internal (leaf imports everywhere, no barrel export) so patch is unambiguous and the import source is uniform. Confirmed no other decodeURIComponent/decodeURI/unescape in the defect class (run-router and the DO fetch handlers split pathname but never decode; INV-1 runIds are [a-z0-9_]).

🤖 Generated with Claude Code

…-auth)

The signal, goal, and schedule routers decoded the threadId/schedule-id path
segment with bare decodeURIComponent before authentication and outside their
try block, and createFlowsafeWorker.fetch wrapped the router calls in no
try/catch — so an unauthenticated request with malformed percent-encoding (e.g.
POST /api/threads/%/message) threw a URIError out of fetch() as a per-request
500. Introduce a shared, zero-dependency safeDecodeSegment leaf (host-kit,
internal — imported directly, not barrel-exported) that treats malformed
encoding as route-absent (byte-identical to a non-matching path); adopt it in
the three routers, the background-tasks read route (whole-class, post-auth), and
dedupe the local copy in the Track E webhook router. Add a top-level try/catch
in the worker fetch handler as defense-in-depth (generic 500, no error.message
leak, structured log). Behavior-preserving for all valid paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 18, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
anchorage-showcase 97cb097 Jul 18 2026, 02:23 AM

@gcharang
gcharang merged commit 65c04ea into dev Jul 18, 2026
3 checks passed
@gcharang
gcharang deleted the fix/pre-auth-decode-hardening branch July 18, 2026 02:25
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.

1 participant