Daily SEO Note — October 25, 2026: A WAF Rule That Breaks Next.js Images
Part of Daily SEO Notes, a daily series.

Audit window: 2026-10-22 06:00 UTC to 2026-10-25 06:00 UTC. Today is a Sunday, so the window is extended to 72 hours for the same reason the Monday rule exists — a strict 24-hour weekend window captures almost nothing. Where an item's primary source carries an earlier date, that date is stated inline rather than rounded forward into today.
SEO for Content Writers
The one confirmed editorial change in this window is small and permanent: Google refreshed its guidance on crawlable URL structures, and the refresh lands on slug conventions every CMS has already baked in. Nothing else shipped for writers. The Search Status Dashboard shows no core, spam, or Discover update running — the most recent was the September 2026 spam update, which started 24 September and ran 13 days 16 hours — so the ranking chatter circulating on 23 October is unconfirmed volatility, not a rollout. The documentation changelog is the only Google surface with an entry inside the window.
Google re-stated its URL word-separation rule: hyphens, never underscores
Google's documentation changelog logged an update on 23 October 2026 to its crawlable URL structure guidance, clarifying word separation with hyphens versus underscores. The page now carries a last-updated stamp of 2026-10-21 UTC and recommends hyphens because underscores are "commonly used for denoting concepts that should be kept together," while hyphens "clearly signal a word boundary." Rollout status: live documentation, non-breaking. This is a clarification of standing guidance, not a new ranking system.
Who it affects: all content, but the real exposure is concentrated in sites migrated from an older CMS, and in faceted or filtered URLs where query parameters were named by a developer rather than an editor. Google's own examples single out all three failure modes — underscore slugs (/summer_clothing), underscore parameter keys (?color_profile=dark_grey), and joined words (/greendress) — and the parameter case is the one editors rarely see, because it never appears in the article title.
What to do differently in the next article: set the slug by hand instead of accepting the auto-generated one, and check that multi-word tag and category slugs use hyphens. What to stop doing: stop treating an underscore slug on an existing, ranking URL as a defect worth fixing. Google's guidance is a recommendation for new URLs, not a demand to redirect an archive; a mass slug rewrite trades a cosmetic win for real redirect-chain and link-equity risk. Fix the pattern going forward, leave the archive alone.
A 503 protects your rankings but freezes your metadata — plan publishing around patch windows
This weekend's engineering story is a patch wave: PHP shipped emergency fixes on 21 October and Node.js shipped a security release the same day. That matters editorially because patching means downtime, and downtime collides with a publishing calendar. The guidance Google reiterated on 21 October is to return HTTP 503 during that window rather than letting requests time out or return 404 or 500.
The part writers need is buried in Google's pausing an online business documentation (last updated 2025-12-10 UTC): while a page returns a 503, "it's not possible for Google's systems to refresh titles, descriptions, metadata, or structured data." The same page caps the tactic at 1–2 days and recommends a retry-after header. So a 503 is not neutral for editorial work — it is a freeze on exactly the fields a rewrite is meant to change.
What to do differently: ask engineering for the patch window before scheduling, and keep title-tag rewrites, meta description tests, and structured-data changes out of it. A new article published into a 503 window is worse than a delayed one, because the URL can be discovered while the content is unavailable. What to stop doing: stop measuring a title or snippet test that overlaps a downtime window — the before-and-after is not comparable, because the refresh never happened.
Unconfirmed: AI Overview citation cards appear to be showing AI-written summaries
Label this unconfirmed. On 23 October, Brodie Clark reported that the citation cards beside Google's AI Overviews were showing an AI-generated summary of the cited page rather than the page's own wording, and Barry Schwartz reproduced it on some test queries but not all. Google has made no statement, there is no documentation change, and there is no rollout identifier. It is a sighting, and it is excluded from the checklist below for that reason.
Why it is worth watching anyway: if a citation card paraphrases rather than quotes, the lever shifts from writing a quotable sentence to making the page's claim unambiguous enough that a paraphrase stays accurate. That is a different craft problem. A hedged, multi-clause definition survives verbatim quoting but degrades badly under summarisation. Do not rewrite anything on the strength of a sighting; note it, and watch whether it persists.
Apply to your next brief
- Set the slug manually: hyphens between words, no underscores, no joined words. Check tag and category slugs too.
- Add a line to the brief naming any filtered or parameterised URL the article links to, so underscore parameter keys get caught before publish.
- Do not open a slug-migration ticket for existing ranking URLs. Apply the convention to new URLs only.
- Confirm the engineering patch window before you schedule, then keep title, meta description, and structured-data changes outside it.
- Discard any snippet or title test whose measurement period overlaps a 503 window, and re-run it clean.
SEO for Developers
One change in this window can take a site's images off the internet today. Cloudflare's emergency WAF release of 25 October 2026 added a rule that matches every request to the Next.js image optimizer path. It defaults to Log, which is safe — unless a ruleset-level override in your account already forces Block, in which case it blocks from the moment it deploys. Everything else is quieter: Next.js shipped a stable patch, and no stable Lighthouse, web-vitals, or Schema.org release landed in the window (web-vitals is still 6.2.3 from 5 October; Schema.org is still 30.1 from 16 September). Cloudflare's 22 October emergency release was metadata-only — seven PHP RCE rules renamed, detection and actions unchanged — so it needs no action.
Breaking risk: Cloudflare's new WAF rule matches every /_next/image request
Identifier and date: WAF Release — 2026-10-25 — Emergency — Cloudflare Managed Ruleset. It adds two detection rules for CVE-2026-111497: "Brotli - Request Content-Encoding - CVE:CVE-2026-111497" and "Next.js - Image Optimizer Path - CVE:CVE-2026-111497". Both ship with a default action of Log. Rollout status: deployed to the Cloudflare Managed Ruleset.
Breaking or non-breaking: non-breaking at the default action, breaking under a pre-existing override. Cloudflare's own note is explicit that the image-optimizer rule matches "legitimate image optimization traffic" as well as hostile requests, that switching it to Block "may prevent optimized images from loading and disrupt image delivery," and that where a ruleset-level override already sets Block, matching requests "may be blocked as soon as the rules are deployed." Exact symptom if ignored: every optimized image on the site returns a WAF block page instead of an image. Downstream, that is an LCP regression on any page whose largest element is an image, and image results dropping out of Google Images and Discover as the fetches fail.
What to change: nothing in the repository — this is an account-level setting. In the Cloudflare dashboard, open WAF → Managed rules → Cloudflare Managed Ruleset and check whether any ruleset-level or tag-level override forces Block. If one does, add a rule-level exception that keeps the Next.js image-optimizer rule on Log while you patch Node.js, which is the actual fix. Then verify from outside the edge that optimized images still return 200.
#!/usr/bin/env bash
# Post-deploy check for the 2026-10-25 Cloudflare emergency WAF release.
set -euo pipefail
# 1. List managed-ruleset overrides in the firewall phase.
curl -sS "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
| jq '.result[]
| select(.phase == "http_request_firewall_managed")
| {id, name, kind}'
# 2. Confirm the optimizer still serves images through the edge.
# Expect 200. A 403 with a Cloudflare block page means an override is on Block.
curl -sS -o /dev/null -w 'optimizer: %{http_code}\n' \
"https://example.com/_next/image?url=%2Fhero.png&w=1920&q=75"
CVE-2026-111497: patch Node.js and restart — the WAF rule is mitigation, not a fix
Identifier and date: CVE-2026-111497, disclosed in the Node.js security release of 21 October 2026, rated High. The advisory describes an out-of-bounds write in the bundled Brotli decoder: an invalid block switch is reported as a temporary need for more input instead of a permanent format error, and the streaming decoder keeps appending bytes to an eight-byte internal buffer. It affects Node.js 26.x, 24.x and 22.x; fixed releases are 22.23.4, 24.22.1 and 26.12.1. The reason it appears in today's window is a status change, not a new disclosure: Cloudflare's managed-rule mitigation shipped on 25 October.
Breaking or non-breaking: non-breaking to upgrade; the exact symptom if ignored is memory corruption in any process that decompresses attacker-influenced Brotli data, which can mean a crash, memory disclosure, or code execution. The SEO-relevant path is the image optimizer, because it fetches remote images. Vercel's advisory states that "for self-hosted Next.js, upgrade Node.js; Next.js does not block Brotli responses in image optimization," that Vercel deployed WAF rules platform-wide the same day, and that managed 22.x and 24.x runtimes are being rolled to patched versions. What to change: the Node version in your base image or runtime pin — and then restart, because a running process keeps the vulnerable decoder loaded until it does.
# CVE-2026-111497 - out-of-bounds write in the bundled Brotli decoder.
# Rebuilding is not enough on its own: a running process keeps the old
# decoder in memory, so the service must also be restarted.
# Pick the patched release on your major line:
# 22.x -> 22.23.4 24.x -> 24.22.1 26.x -> 26.12.1
FROM node:24.22.1-bookworm-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
CMD ["npm", "start"]
# Verify inside the running container, not just in the image:
# docker compose exec web node -p "process.versions.node"
Next.js 16.4.3 fixes extensionless Google Font URLs in both bundlers
Identifier and date: Next.js v16.4.3, published 23 October 2026 and now the latest stable tag. Rollout status: released, and explicitly a backport — the release note says it "is backporting bug fixes" and "does not include all pending features/changes on canary." Breaking or non-breaking: non-breaking. Nothing in it touches the Metadata API, app/sitemap.ts, app/robots.ts, or revalidation semantics; a Turbopack loader-invalidation change was reverted rather than shipped.
The one entry worth a developer's attention is "Fix extensionless Google font URLs in both bundlers" (#100277). The symptom if ignored is a font request that resolves incorrectly, and a mis-resolved webfont shows up in field data rather than in a build error: text that paints late pushes LCP out when the largest element is a heading, and a late-swapping font contributes to CLS. What to change: the next dependency pin. This is a patch release on the same major, so it is a version bump and a Core Web Vitals re-measurement, not a migration.
#!/usr/bin/env bash
# Next.js 16.4.3 (stable, 23 Oct 2026) - backported bug fixes only.
set -euo pipefail
npm install [email protected]
npm run build
# Confirm no extensionless Google Fonts URL survived into the built CSS.
# Every match should end in .woff2 (or another real extension).
grep -rhoE 'url\([^)]*fonts\.gstatic[^)]*\)' .next/static/css/ | sort -u
# Re-measure after deploying; this bump can move LCP and CLS in field data.
npx unlighthouse-ci --site https://example.com || true
Standing policy worth re-reading this week: robots.txt is an access protocol, not a usage licence
No AI-crawler policy changed inside this window: OpenAI, Perplexity and Cloudflare published no crawler-control changes between 22 and 25 October. This item is standing policy, included because it is where the week's AI-crawler questions keep landing, and because getting it wrong is a silent, long-lived mistake. RFC 9309 (September 2022) defines user-agent matching in section 2.2.1 and the Allow/Disallow lines in section 2.2.2 — and that is all it defines. It governs what a compliant crawler may fetch. It says nothing about what happens to the content afterwards, so a robots.txt rule is an access preference, not a restriction on use.
The practical consequence is that training, search, and user-triggered fetching are three separate decisions that happen to share one file, and each needs its own user-agent token. Google's common crawlers documentation (last updated 2026-10-15 UTC) is the clearest statement of the distinction: Google-Extended is "a standalone product token" used "in a control capacity" over Gemini training and grounding, it is not a crawler with its own user agent, and it "does not impact a site's inclusion in Google Search." What to change: public/robots.txt, one block per token, with the search fetchers and the training fetchers decided independently rather than as a single allow-or-deny.
# Access preferences only (RFC 9309 s2.2.1 - s2.2.2).
# Search fetchers and training fetchers are separate decisions.
# --- Search / answer surfaces: allow, so the site stays citable ---
User-agent: OAI-SearchBot
Allow: /
User-agent: Claude-SearchBot
Allow: /
User-agent: PerplexityBot
Allow: /
# --- Training fetchers: deny without affecting search eligibility ---
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: CCBot
Disallow: /
# --- Control token, not a crawler ---
# Governs Gemini training and grounding. Does NOT affect Google Search
# inclusion and is not a ranking signal.
User-agent: Google-Extended
Disallow: /
Sitemap: https://example.com/sitemap.xml
Ship today
- Check your Cloudflare Managed Ruleset for a ruleset-level or tag-level Block override, before the new Log-default rules inherit it. If one exists, exempt the Next.js image-optimizer rule.
- Request /_next/image from outside your network and confirm a 200, not a block page. Do this from the edge, not from localhost.
- Pin Node.js to 22.23.4, 24.22.1 or 26.12.1, rebuild, and restart the service. Verify process.versions.node inside the running container, not in the image.
- Bump next to 16.4.3, rebuild, and re-measure LCP and CLS on a template whose largest element is text.
- Audit public/robots.txt for a single blanket AI rule, and split it into per-token decisions for search, training, and user-triggered fetching.
Comments
Share your thoughts and join the conversation



