Skip to content

[NO-TICKET] Deliver detection reports on Nitro-built Workers (Lovable) - #451

Merged
mariojgt merged 1 commit into
mainfrom
mariot/workers-request-waituntil
Oct 26, 2026
Merged

mariojgt merged 1 commit into
mainfrom
mariot/workers-request-waituntil

Conversation

@mariojgt

Copy link
Copy Markdown
Contributor

What changed

On Lovable's current template, blocking works but the firewall log stays empty. That template builds with Nitro for Cloudflare Workers.

Why the reports were lost: Cloudflare calls the Worker with (request, env, ctx), but Nitro calls the app's fetch with the request alone. It puts the host's waitUntil on the request itself (request.waitUntil, plus request.runtime.cloudflare.context). The guard's fetch() only looked for waitUntil in an argument beside the request. It found none, so it returned the 403 with the report still in flight, and Cloudflare cut the report off when the response went out.

src/protect/runtime.js

AGENT-INSTALL.md: a short "Delivery" note in "Runtime guard reporting" says when reports are sent, and the background-check sentence names where waitUntil is found.

How it was verified

  • Real Lovable build: I rebuilt a Lovable app's Worker (Nitro, cloudflare-module preset) with this runtime and called it as Cloudflare does, fetch(request, env, ctx), against a stubbed Patchstack API. The attack got 403, the report was handed to waitUntil (1 item), and it reached POST …/detections/<uuid>. Before this change nothing was handed over.
  • New tests in tests/protect/rules-reader.test.ts, which all fail on the previous runtime:
    • a Nitro-style request carrying waitUntil;
    • one carrying runtime.cloudflare.context;
    • a host with no waitUntil, behind a deliberately slow detections endpoint, where the report must be delivered before the 403 is returned.
  • Gates: npm run typecheck, npm run build, full npm test (4625 passed), capabilities:check are green. An earlier full run had 4 timing tests time out under load. Each passes alone, and the one touching setup takes the same ~1.2s on this branch and on main.

Rollout

  • Apps pick it up when they update @patchstack/connect and republish. No setup re-run is needed.
  • AGENT-INSTALL.md changes, so the hostile field test is owed after the release that carries this, plus lovable for doc accuracy.

🤖 Generated with Claude Code

Lovable's current template builds with Nitro for Cloudflare Workers.
Nitro calls the app's fetch with the request alone and puts the host's
waitUntil on the request itself. The guard's fetch() looked for waitUntil
only in an argument beside the request, so on these apps it found none
and returned the 403 with the report still in flight: Cloudflare cut it
off and the firewall log stayed empty while blocking worked.

- hostWaitUntil finds waitUntil beside the request, on the request
  (request.waitUntil) or on request.runtime.cloudflare.context. The
  background rules check from #443 uses it too.
- When a host offers none, fetch() delivers in the request as
  fetchGuard already does: a block waits up to 2 seconds for its report,
  and a detect-only report goes out on a later request once stale. The
  two paths share one routine.
- AGENT-INSTALL.md says when reports are sent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderbuds

coderbuds Bot commented Oct 26, 2026

Copy link
Copy Markdown

🎯 Elite quality (95%) — Extracts a shared hostWaitUntil helper so Nitro-style request-attached waitUntil works for reports and rule refresh.

📦 Medium

See how your team is trending →

@mariojgt

Copy link
Copy Markdown
Contributor Author

/review

@mariojgt
mariojgt merged commit e276cf8 into main Oct 26, 2026
23 checks passed
@mariojgt
mariojgt deleted the mariot/workers-request-waituntil branch October 26, 2026 11:02
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