wrangler
Caching responses that depend on Authorization/Cookie headers without varying cache key leaks one user's response to another.
`Math.random()` is not cryptographically secure — it's predictable. Use `crypto.randomUUID()` or `crypto.getRandomValues()` (Web Crypto is available on Workers without import).
D1 SQL injection: template-literal interpolation or `+` concatenation in `.prepare()`/`.exec()` is injectable. Use parameterized queries: `db.prepare('SELECT * FROM t WHERE id = ?').bind(id)`.
Durable Object handlers that initialize state from storage should wrap the load in `this.state.blockConcurrencyWhile(async () => {...})` in the constructor to prevent request handlers from observing partially-loaded state.
Logging the entire `env` object exposes every bound secret (from `wrangler secret put`) to `wrangler tail`, Logpush, and any connected Logs-to-SIEM pipeline. Log specific non-secret fields only.
`fetch()` without `AbortSignal.timeout()` relies on Workers' 30s CPU-time ceiling (or subrequest ceiling) — a slow upstream can consume the whole request budget. Add an explicit timeout appropriate to the call.
Workers have a 50-subrequest limit on Free and 1000 on Paid plans — unbounded loops issuing `await fetch()` will throw `Too many subrequests` mid-execution. Batch, parallelize with Promise.all up to the limit, or offload to a Queue.
CVE-2026-3125: @opennextjs/cloudflare <1.6.3 has an SSRF via path normalization in the /cdn-cgi/image/ handler, letting attackers fetch arbitrary remote URLs through your Worker. Upgrade to the patched release.
Comparing a secret/token with `===` leaks length and prefix via timing side-channel (attacker can brute-force byte-by-byte). Use `crypto.subtle.timingSafeEqual(enc(a), enc(b))` (Web Crypto on Workers) after length-checking.
GHSA-4pfg-2mw5-f8jx: @cloudflare/vite-plugin <0.1.6 exposes Worker secrets over the dev-server without authentication, so any local process can read them. Upgrade and avoid binding production secrets in `vite dev`.
Running ad-hoc SQL directly against remote D1 skips review and leaves no migration trail.
Applying migrations to a remote (production) D1 database.
Destructive SQL (DROP / TRUNCATE / unbounded DELETE) against --remote D1 is irreversible — D1 has no native point-in-time recovery on lower tiers. Run against --preview or a named preview database first, and always include a WHERE clause on mutations.
`wrangler deploy` without `--env` targets the top-level (production) worker.
Hyperdrive connection strings containing DB credentials in wrangler.toml get committed to git. Store the URL with `wrangler hyperdrive create --connection-string=...` (server-side) and reference the binding id; for local dev put the URL in `.dev.vars` (gitignored).
KV deletions are immediate and non-recoverable. Confirm the namespace ID, scope deletion with a prefix, and list keys first via `wrangler kv key list`.
`wrangler login` uses OAuth and requires a browser — it cannot complete in CI. Use CLOUDFLARE_API_TOKEN (scoped to the account/zone/workers) set as a secret environment variable.
No `main` entry in wrangler.toml — deploy will fail unless main is passed via CLI. Declare the entry point explicitly for reproducible deploys.
Missing `compatibility_date` in wrangler.toml. Without it, Workers runtime behavior is undefined and may break on deploy. Set to today's date or a pinned date matching tested behavior.
node_compat = true (webpack polyfills) is deprecated and removed in wrangler v4. Switch to the `nodejs_compat` compatibility_flag for native workerd Node APIs.
CVE-2026-0933 (GHSA-36p8-mvp6-cv38): `--commit-hash` on `wrangler pages deploy` is passed to a shell and allows OS command injection in wrangler <=3.114.16 and 4.x <=4.59.0. Upgrade wrangler and restrict the value to `[A-Fa-f0-9]+` before passing it.
public_bucket = true makes every object in the R2 bucket world-readable via the r2.dev URL. Use a Worker or signed URLs for controlled access. Only enable for exclusively public assets.
`wrangler r2 bucket delete` permanently destroys the bucket and all objects. There is no undo. Use object-level deletion (`wrangler r2 object delete`) if clearing contents, and verify the bucket name.
`wrangler rollback` reverts the active deployment but does NOT roll back D1 migrations, KV writes, or R2 objects made by the newer version.
Secrets in wrangler.toml [vars] are committed to git and visible in plaintext on the Cloudflare dashboard. Use `wrangler secret put NAME` (encrypted at rest, env-scoped). The binding name stays identical — only storage changes.
Piping secrets via `echo | wrangler secret put` writes them to shell history and may appear in `ps` output. Pipe from a file (`wrangler secret put NAME < file`) or use interactive mode, then clear the file.
compatibility_date is more than 3 years old. Recent Workers features (nodejs_compat v2, streaming, Python support) require dates >= 2024. Review the runtime changelog before bumping.
`wrangler tail` on production streams live request data including headers and URLs — may expose user PII or auth tokens to the terminal and any tee'd logs. Use `--format=json --filter` to scope.
`usage_model` in wrangler.toml is ignored as of 2024 — billing is set per-account on the dashboard (Standard/Unbound). Remove this field to avoid confusion.
A bare `*` route catches every request on every zone in the account — it will hijack traffic from unrelated sites. Scope routes: `example.com/api/*` or `*.example.com/*`.