Skip to content

Changelog

New updates and improvements at Cloudflare.

New scheduling policy for Containers to configure image and instance from Durable Objects

Containers now support the durable_object scheduling policy in public beta. This policy lets a Durable Object select the image and instance size for a Container at runtime instead of using one centrally managed configuration for the application.

To use custom images, configure the policy and one or more named images in Wrangler:

{
	"containers": [
		{
			"class_name": "AgentComputer",
			"scheduling_policy": "durable_object",
			"images": {
				"base": {
					"dockerfile": "./container/Dockerfile",
				},
			},
		},
	],
}
[[containers]]
class_name = "AgentComputer"
scheduling_policy = "durable_object"

[containers.images.base]
dockerfile = "./container/Dockerfile"

Wrangler prepares each image and exposes its immutable reference through ctx.container.images. Supply that reference and an instance size when you start the Container:

src/index.jsjs
this.ctx.container.start({
	image: this.ctx.container.images.base,
	enableInternet: false,
	instance: "standard-2",
});
src/index.tsts
this.ctx.container.start({
	image: this.ctx.container.images.base,
	enableInternet: false,
	instance: "standard-2",
});

The durable_object policy also supports the new cloudflare/debian-trixie Cloudflare-managed image, which includes Node.js 24.20.0 on Debian Trixie slim. Start it directly without configuring a named image.

Durable Object-managed Container instances have independent lifecycles and do not participate in application-wide image rollouts.

For configuration, runtime sizing, snapshots, and update behavior, refer to Scheduling Policies.

Snapshot and restore Container filesystem

Containers now support snapshot APIs in public beta for saving and restoring point-in-time filesystem state. Create a snapshot first, then pass it back to start() to restore files after container sleep, restart, or handoff to another Durable Object.

Use snapshotContainer() through the Durable Object Container API to capture the full container filesystem. Create a snapshot from a running Container, store its handle, and pass that handle to start() when you restore it later:

src/index.jsjs
import { DurableObject } from "cloudflare:workers";

export class MyDurableObject extends DurableObject {
	async saveSnapshot() {
		// Create a snapshot from the running Container.
		const containerSnapshot = await this.ctx.container.snapshotContainer({});

		await this.ctx.storage.put("containerSnapshot", containerSnapshot);
	}

	async restoreSnapshot() {
		// Restore the saved snapshot later.
		const containerSnapshot = await this.ctx.storage.get("containerSnapshot");

		if (!containerSnapshot) {
			return;
		}

		this.ctx.container.start({ containerSnapshot, enableInternet: false });
	}
}
src/index.tsts
import { DurableObject } from "cloudflare:workers";

export class MyDurableObject extends DurableObject {
	async saveSnapshot() {
		// Create a snapshot from the running Container.
		const containerSnapshot = await this.ctx.container.snapshotContainer({});

		await this.ctx.storage.put("containerSnapshot", containerSnapshot);
	}

	async restoreSnapshot() {
		// Restore the saved snapshot later.
		const containerSnapshot =
			await this.ctx.storage.get<ContainerSnapshot>("containerSnapshot");

		if (!containerSnapshot) {
			return;
		}

		this.ctx.container.start({ containerSnapshot, enableInternet: false });
	}
}

Snapshots are only supported for Container applications that use the durable_object scheduling policy. Snapshots are immutable, so create a new snapshot to persist filesystem changes made after a restore.

For more information, refer to Snapshots and the Durable Object Container API.

Cloudflare One Client for Windows (version 2026.8.2028.1)

A new Beta release for the Windows Cloudflare One Client is now available on the beta releases downloads page.

This beta release includes the following changes and improvements:

  • Fixed an issue that could briefly block traffic to split tunnel excluded resources while the client was connecting or reconnecting.
  • Improved reauthentication reliability and fixed an issue where a reauthentication could force a new registration.
  • Improved client reaction to the current network lowering its MTU.
  • Added support for routing non-RFC 1918 local IPv4 networks through the WARP tunnel when unrestricted LAN inclusion is enabled by policy or MDM.
  • Improved DNS reliability on networks with lower MTUs by clamping the TCP maximum segment size (MSS) for DNS-over-HTTPS connections sent through the tunnel.
  • Improved API reliability by retrying requests dropped when reusing pooled connections.
  • The client no longer requires the Windows WLAN AutoConfig service to be running.
  • Implemented a service recovery mechanism backed by Windows scheduler task to start WARP service on system unlock if not already started.
  • Fixed slow captive portal checks causing the client service to become unresponsive or restart while connecting.
  • Fixed a race when switching tunnel protocols during key rotation that could prevent WireGuard from connecting.
  • Fixed the client continuing to report 'No network' after a successful manual disconnect.
  • Fixed Digital Experience Monitoring (DEX) HTTP tests failing TLS validation on Windows.
  • Fixed the client UI crashing at startup when it could not write to the Windows registry.
  • Fixed latency spikes and traffic interruptions during TPM-backed API authentication when hardware-backed registration is enabled.
  • Fixed trailing whitespace in BIOS serial numbers causing serial-number and client-certificate device posture checks to fail.
  • Fixed a client UI crash that could occur when the daemon connection was reset during an IPC request.
  • Fixed a startup crash when date formatting data for the system locale had not yet loaded.

Known issues

  • None

Cloudflare One Client for macOS (version 2026.8.2028.1)

A new Beta release for the macOS Cloudflare One Client is now available on the beta releases downloads page.

This beta release includes the following changes and improvements:

  • Fixed an issue that could briefly block traffic to split tunnel excluded resources while the client was connecting or reconnecting.
  • Improved reauthentication reliability and fixed an issue where a reauthentication could force a new registration.
  • Improved client reaction to the current network lowering its MTU.
  • Added support for routing non-RFC 1918 local IPv4 networks through the WARP tunnel when unrestricted LAN inclusion is enabled by policy or MDM.
  • Improved DNS reliability on networks with lower MTUs by clamping the TCP maximum segment size (MSS) for DNS-over-HTTPS connections sent through the tunnel.
  • Improved API reliability by retrying requests dropped when reusing pooled connections.
  • Fixed Extra Logging failing to capture packets across all interfaces.
  • Fixed an issue that could prevent remote diagnostics from completing.
  • Fixed DNS connectivity checks failing on IPv6-only networks.
  • Fixed the client service exiting when its route-monitoring socket was closed after sleep or wake.
  • Fixed DNS enforcement checks making the client service unresponsive on systems with large routing tables.
  • Fixed slow captive portal checks causing the client service to become unresponsive or restart while connecting.
  • Fixed a race when switching tunnel protocols during key rotation that could prevent WireGuard from connecting.
  • Fixed the client continuing to report 'No network' after a successful manual disconnect.
  • Fixed a client UI crash that could occur when the daemon connection was reset during an IPC request.
  • Fixed a startup crash when date formatting data for the system locale had not yet loaded.

Known issues

  • None

Identify model overuse and potential savings with User Insights

AI Gateway User Insights now gives you more context about the traffic flowing through your gateway. It shows what users and agents are doing with AI, and where a selected model may be more capable than a task requires.

On the analysis side, User Insights groups conversations by task, tracks conversation turns, and helps you compare model fit with cost and latency.

User Insights task and model analysis grouped by task categories

The Potential Savings view highlights requests that may work with faster or less expensive models without compromising output quality. These are the same signals that Cloudflare's Auto Router uses to select a model based on task and cost.

Potential Savings view comparing tasks and suggested models

These new insights are available to all AI Gateway customers at no additional cost. For more information, refer to User Insights.

Connect multiple clients to one Browser Run session

Browser Run sessions now accept multiple concurrent connections. Before, a session accepted only one connection at a time, and other Workers had to wait until that connection closed. Now multiple Workers can connect to the same browser at the same time.

Each puppeteer.connect() call opens its own Chrome DevTools Protocol (CDP) connection. Create a separate browser context for each request to keep its pages, cookies, and storage apart from other clients.

const browser = await puppeteer.connect(env.MYBROWSER, sessionId);
const context = await browser.createBrowserContext();

try {
	const page = await context.newPage();
	await page.goto("https://example.com");
	// ...
} finally {
	await context.close();
	await browser.disconnect(); // keep the shared browser running
}
const browser = await puppeteer.connect(env.MYBROWSER, sessionId);
const context = await browser.createBrowserContext();

try {
	const page = await context.newPage();
	await page.goto("https://example.com");
	// ...
} finally {
	await context.close();
	await browser.disconnect(); // keep the shared browser running
}

Sharing sessions means fewer new browsers to launch, less cold-start time, and fewer concurrent browsers counted against your limits.

Concurrent connections require @cloudflare/puppeteer version 1.1.0 or later.

Refer to Reuse sessions for a full example.

Custom Container instance types no longer have a disk to memory ratio limit

Containers custom instance types no longer limit disk based on memory. Previously, a custom instance type could have a maximum of 2 GB of disk for each 1 GiB of memory. You can now allocate up to the 20 GB disk maximum to any custom instance type.

Use this to run workloads that need more disk than memory, such as workloads with large container images, datasets, or build caches. The maximum image size is the same as the instance disk space, so more disk also lets you deploy larger images.

For example, a custom instance type with 1 vCPU and 3 GiB of memory was previously limited to 6 GB of disk. It can now use 20 GB:

{
	"containers": [
		{
			"image": "./Dockerfile",
			"instance_type": {
				"vcpu": 1,
				"memory_mib": 3072,
				"disk_mb": 20000,
			},
		},
	],
}
[[containers]]
image = "./Dockerfile"

  [containers.instance_type]
  vcpu = 1
  memory_mib = 3_072
  disk_mb = 20_000

The other custom instance type constraints do not change, including the minimum of 3 GiB of memory per vCPU. For the full list, refer to Custom Instance Types.

Identify Mesh, Workers VPC, and Cloudflare Tunnel replicas in network logs

You can now tell a person on a laptop apart from a Mesh node or an AI agent running on Workers, without matching on connector email addresses or Mesh IP ranges — and see exactly which Cloudflare Tunnel and cloudflared replica received each session.

Gateway network logs and Zero Trust Network Session Logs now identify two new kinds of traffic:

  • Mesh — Traffic sent from or delivered to a Cloudflare Mesh node. Previously, Mesh nodes were logged the same way as devices running the Cloudflare One Client, because Mesh nodes run the client in headless mode.
  • Workers VPC — Traffic sent by a Worker through a Workers VPC binding. Previously, Workers VPC sessions were not recorded in Network Session Logs.
Viewing Mesh and Workers VPC traffic in Gateway network logs

Gateway network logs

To view these values in the dashboard, go to Zero Trust > Insights & Logs > Logs > Network logs, select Columns, and turn on Traffic Source and Traffic Destination. Both values also appear under Network query details when you open a log entry.

Network Session Logs

The zero_trust_network_sessions dataset, available through Logpush, includes the following fields:

Field Description
OnrampType How the session entered Cloudflare One. Values: CF1_CLIENT, MESH, WORKERS_VPC, MAGIC, OTHER.
Offramp Where the session was routed. Sessions routed to a Mesh node report MESH.
SourceName Name of the Worker that started the session. Only populated for Workers VPC sessions.
SourceID Stable identifier of the Worker that started the session. Only populated for Workers VPC sessions.
DestinationReplicaID The replica that served the session, such as a specific replica of a Mesh node or a cloudflared replica of a Cloudflare Tunnel.

For example, OnrampType = 'WORKERS_VPC' AND Offramp = 'MESH' returns every session where a Worker reached a service behind a Mesh node, and SourceName tells you which Worker it was.

See which tunnel and replica received a session

With DestinationReplicaID, you can now confirm which Cloudflare Tunnel and which cloudflared replica received traffic for a specific session. Combine it with the existing DestinationTunnelID field to trace a session to an exact tunnel replica — or Mesh node replica — when you run multiple replicas for high availability. The replica ID matches the Connector ID shown in the dashboard, so you can stream that replica's logs with cloudflared tail --connector-id.

Sessions logged before this change are not backfilled. For all available fields, refer to Zero Trust Network Session Logs.

Browser Run adds WebMCP to Kitesurf and moves to document.modelContext

WebMCP now works in Kitesurf sessions as well as Lab sessions. Both backends use the document.modelContext API from the WebMCP Community Group draft ↗︎. Lab sessions no longer expose navigator.modelContextTesting.

To list and run page tools:

  • Chrome DevTools: Use the Application > WebMCP panel in the live view of a Lab session or in the Kitesurf playground ↗︎.
  • AI agents: Start Chrome DevTools MCP with the --category-experimental-webmcp flag to add the list_webmcp_tools and execute_webmcp_tool tools.
  • CDP clients: Use the WebMCP CDP domain.

Invalidate cached content instead of purging it

You can now invalidate cached content instead of purging it. Invalidation marks matching content as stale. On the next request, Cloudflare revalidates the content with your origin. If your origin responds with 304 Not Modified, Cloudflare reuses the cached content instead of downloading it again.

Use invalidation to refresh a group of assets when only some of them have changed. For example, invalidate all content that shares a cache tag. Cloudflare reuses unchanged assets instead of downloading them again. This requires your origin to return an ETag or Last-Modified header and support conditional requests.

Invalidation supports the same selectors as purge: URLs, cache tags, hostnames, URL prefixes, and everything. To invalidate content, send a POST request to the new invalidate_cache endpoint:

curl --request POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/invalidate_cache" \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"tags":["product-images"]}'

In the dashboard, use Invalidate Cache on the Caching > Configuration page.

Your cache settings determine whether Cloudflare serves stale content while it revalidates. Cloudflare can also serve invalidated content stale if your origin returns a 5xx error or cannot be reached. To stop serving cached content, purge it instead.

Invalidation requests count toward the same rate limits as purge requests.

Purge behavior for Cache Reserve also changes with this release. For details, refer to Cache Reserve purge behavior.

For more information, refer to Invalidate cached content.

Purge now forces a cache miss for Cache Reserve content

Purge requests now force a cache miss for Cache Reserve content, regardless of purge type. Previously, purging by cache tag, hostname, prefix, or everything marked matching Cache Reserve content for revalidation. Purging by URL already removed content from Cache Reserve and is unchanged.

This change applies to purge requests from the API and the dashboard. Cache Reserve now handles purges the same way as the edge cache.

Cost impact

After a purge, the next request for affected content is a Cache Reserve miss. Your origin must deliver the content in full, even if it has not changed. Cloudflare then writes the content to Cache Reserve again, which is billed as a Class A operation.

Purging by tag, hostname, prefix, or everything does not delete content from Cache Reserve right away. Matching content continues to incur storage costs until a later request replaces it or its retention period ends.

If you frequently purge Cache Reserve content by tag, hostname, prefix, or everything, review the effect on your origin egress and Cache Reserve usage.

Keep revalidating Cache Reserve content

To keep content in Cache Reserve and revalidate it instead, send the same request to the new invalidate_cache endpoint:

curl --request POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/invalidate_cache" \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"tags":["product-images"]}'

In the dashboard, use Invalidate Cache on the Caching > Configuration page.

If your origin responds with 304 Not Modified, Cloudflare reuses the stored content instead of fetching it from your origin again. Compared with purging, invalidation reduces origin egress but not Cache Reserve operations. Updating the stored content after a 304 response is still a Class A operation. Invalidating by URL also updates the stored content when you send the request, which is a Class A operation.

Unlike the previous purge behavior, invalidation can serve stale content while it revalidates if your cache settings allow it. This applies only to copies in the edge cache, not to content served from Cache Reserve. Cloudflare can also serve invalidated content stale if your origin returns a 5xx error or cannot be reached. For details, refer to Invalidate cached content.

Cloudflare CLI is now in beta

The Cloudflare CLI, cf, is now in beta. cf is one command-line interface for the public Cloudflare API and for Workers projects. Use it to manage zones, DNS, storage, and security settings, and to create, develop, and deploy Workers, without switching between tools.

Install cf globally, then sign in:

npm install --global cf
cf auth login

With cf, you can:

  • Manage resources across Cloudflare. More than 2,900 commands cover the public Cloudflare API, and most print their results as JSON.
  • Create and deploy Workers. cf init creates a project that uses cloudflare.config.ts, a typed configuration file. cf dev, cf build, and cf deploy develop, build, and deploy it.
  • Move from Wrangler. cf migrate converts a Wrangler configuration file to cloudflare.config.ts. You can also run cf resource commands in an existing Wrangler project without migrating it.
  • Work with coding agents. cf cli search finds the command for a task from a plain-language description, so an agent can find and run commands without prior knowledge of cf.

cf is in beta. Commands, configuration, and Build Output can change before the stable release.

To get started, refer to Install and sign in. To move an existing project, refer to Migrate a Wrangler project.

Call Workflows declared in `exports` through `ctx.exports`

A Worker can now call the Workflows it declares in the exports field of its Wrangler configuration through ctx.exports. You no longer need a workflows binding to call a Workflow from the Worker that defines it.

Each Workflow is keyed by class name, and has the same API as a Workflow binding:

src/index.jsjs
export default {
	async fetch(request, env, ctx) {
		const instance = await ctx.exports.MyWorkflow.create({
			params: { name: "World" },
		});
		return Response.json({ id: instance.id });
	},
};
src/index.tsts
export default {
	async fetch(request, env, ctx): Promise<Response> {
		const instance = await ctx.exports.MyWorkflow.create({
			params: { name: "World" },
		});
		return Response.json({ id: instance.id });
	},
} satisfies ExportedHandler<Env>;

A workflows binding and a workflow export with the same name share their instances. You can move a Workflow from a binding to an export without losing its instances.

wrangler dev, the Cloudflare Vite plugin, and the Workers Vitest integration run Workflows on ctx.exports locally. Local development requires Wrangler 4.142.0, @cloudflare/vite-plugin 1.61.0, or @cloudflare/vitest-plugin 1.3.0 or above.

In Vitest, introspectWorkflow() and introspectWorkflowInstance() still need a Workflow binding. To introspect a Workflow declared in exports, add a test-only binding to it.

For more information, refer to Call a Workflow through ctx.exports.

Subscribe to Browser Run crawl events

Browser Run crawl jobs can publish lifecycle events to Cloudflare Queues. Subscribe to started, updated, and finished events to track progress or trigger downstream processing without polling.

To create an account-level subscription, run the following command:

npx wrangler queues subscription create <QUEUE_NAME> --source browserRun --events crawl.started,crawl.updated,crawl.finished

For payload examples, refer to the Browser Run event schemas.

Suppress recipients for one sending domain

Email Sending suppressions now have a scope:

  • account: The suppression applies to every sending domain and subdomain in your account. This is the default.
  • sending_domain: The suppression applies to one sending domain only. A suppression for mail.myappexample.com does not block mail from myappexample.com.

Most importantly, Email Sending now automatically creates bounce and complaint suppressions at the sending-domain level. This provides greater granularity by preventing an issue with one sending domain from suppressing the recipient across your entire account.

To add a suppression for one sending domain in the dashboard, go to Email Sending > Suppressions and select Sending domain in Scope. Imports can also set a scope for each row or a default scope.

In the API, pass scope when you create the suppression:

curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/email/sending/suppressions \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "email": "user@example.net",
    "scope": { "type": "sending_domain", "value": "mail.myappexample.com" }
  }'

The suppressions API returns scope on every suppression. To list the suppressions for one domain, use scope_type=sending_domain&scope_value=mail.myappexample.com. If you omit scope, the API creates an account suppression, so existing integrations continue to work.

Refer to Suppression lists and Manage suppressions for details.

WAF Release - 2026-09-25 - Emergency

This update provides immediate defense against critical vulnerabilities affecting WordPress and JFrog Artifactory, including path traversal, local file inclusion (LFI), cross-site scripting (XSS), and authentication bypass exploits.

Key Findings

  • CVE-2026-87902: A high-severity Path Traversal and Local File Inclusion (LFI) vulnerability affecting WordPress. Unauthenticated attackers can exploit this flaw to read arbitrary files on the host server, potentially exposing sensitive configuration data or system files.

  • CVE-2026-42018 & CVE-2026-82329: Critical authentication bypass vulnerabilities affecting JFrog Artifactory. Successful exploitation allows unauthenticated attackers to bypass security controls and achieve unauthorized access to the Artifactory instance.

Impact

We strongly recommend that administrators apply the latest vendor patches for WordPress and JFrog Artifactory to fully secure origin servers.

Detailed Rule Changes

RulesetRule IDLegacy Rule IDDescriptionPrevious ActionNew ActionComments
Cloudflare Managed RulesetN/AWordpress - Path Traversal, Local File Inclusion - CVE:CVE-2026-87902N/ABlockThis is a new detection.
Cloudflare Managed RulesetN/AWordpress - XSS - CommentN/ABlockThis is a new detection.
Cloudflare Managed RulesetN/AJFrog Artifactory - Authentication Bypass - CVE:CVE-2026-42018N/ABlockThis is a new detection.
Cloudflare Managed RulesetN/AJFrog Artifactory - Authentication Bypass - CVE:CVE-2026-82329N/ABlockThis is a new detection.

Workers tracing — new getActiveSpan(), recordException(), startSpan(), and setAttributes() APIs

Custom spans in Workers now support more of the OpenTelemetry span API, so you can instrument more of your code and record errors directly on your spans.

  • tracing.startSpan(name) creates a span without making it the active span, and returns it. Other spans do not nest under it. Call span.end() when the operation is complete.
  • tracing.getActiveSpan() returns the currently active span. Use it to annotate the current span from helper functions and libraries without passing the span object through your code. Outside any custom span, it returns the invocation's root span.
  • span.recordException(exception) records an exception event on a span. It accepts an Error, a string, or an object with a code, name, or message.
  • span.setAttributes(attributes) sets multiple attributes at once. setAttribute() and setAttributes() now return the span, so you can chain calls.
src/index.jsjs
import { tracing } from "cloudflare:workers";

export default {
	async fetch(request, env) {
		const user = await authenticate(request, env);

		// Annotate the invocation's root span
		tracing.getActiveSpan()?.setAttributes({
			"user.id": user.id,
			"user.plan": user.plan,
		});

		const span = tracing.startSpan("load-profile");
		try {
			return Response.json(await loadProfile(env, user.id));
		} catch (err) {
			span.recordException(err);
			throw err;
		} finally {
			span.end();
		}
	},
};
src/index.tsts
import { tracing } from "cloudflare:workers";

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const user = await authenticate(request, env);

		// Annotate the invocation's root span
		tracing.getActiveSpan()?.setAttributes({
			"user.id": user.id,
			"user.plan": user.plan,
		});

		const span = tracing.startSpan("load-profile");
		try {
			return Response.json(await loadProfile(env, user.id));
		} catch (err) {
			span.recordException(err as Error);
			throw err;
		} finally {
			span.end();
		}
	},
};

For more details, refer to the custom spans documentation.

See every release and gradual deployment on Workers Metrics charts

Workers Metrics charts now show every release in the selected time range, including the full progression of gradual deployments. This makes it easier to correlate changes in memory, CPU time, errors, or latency with the code that was serving traffic.

Memory usage chart showing a gradual deployment as a shaded rollout band

A gradual deployment appears as a single rollout across the chart, with shading that increases as more traffic moves to the new version. Hover over a rollout to see the previous and new versions, the rollout duration, and the traffic percentage configured at each step.

Invocations chart showing traffic shifting from the previous version to the new version during a gradual deployment

Use these annotations to:

  • Find when a regression started — See which traffic percentage was configured when errors, latency, CPU time, or wall time changed.
  • Compare rollout stages — Check whether a metric changed as more traffic moved to the new version.
  • Confirm rollbacks — Rollbacks appear as separate release events, so you can check whether metrics recovered after a rollback.

Direct deployments that send 100% of traffic to a single version still appear as individual markers. Nearby direct deployments are grouped to reduce visual clutter. Versions that are only uploaded, or only configured at 0%, do not appear on metrics charts.

To view release annotations, open the Metrics tab for your Worker ↗︎.

RFC 8509 root key trust anchor sentinel support

1.1.1.1 now supports RFC 8509 ↗︎ root key trust anchor sentinels. They let you check whether the responding resolver trusts a DNSSEC root key ahead of a key rollover.

To check for KSK-2024 (key tag 38696), query DNSSEC-signed names in dnstest.dev:

# On a sentinel-aware resolver that trusts KSK-2024:

# Returns NOERROR with an A answer.
dig @1.1.1.1 root-key-sentinel-is-ta-38696.dnstest.dev. A +noall +comments +answer

# Returns SERVFAIL without an answer.
dig @1.1.1.1 root-key-sentinel-not-ta-38696.dnstest.dev. A +noall +comments +answer

# CD bypasses sentinel processing and returns the original A answer.
dig @1.1.1.1 root-key-sentinel-not-ta-38696.dnstest.dev. A +cdflag +noall +comments +answer

For background on DNSSEC validation, refer to DNSKEY.

MCP server portals are now generally available

MCP server portals are now generally available to all Cloudflare customers. A portal gives users one endpoint for approved Model Context Protocol (MCP) servers. Cloudflare Access logs tool, prompt, and resource activity.

Since the open beta, MCP server portals have added:

To create a portal and connect an MCP client, refer to MCP server portals.

Declare Workflows in the `exports` configuration

You can now declare the Workflows a Worker defines in the exports field of your Wrangler configuration file. Previously, a Worker could only define a Workflow through a workflows binding, even when the Worker never called the Workflow itself.

Key each entry by the name of the class that extends WorkflowEntrypoint:

{
	"exports": {
		"MyWorkflow": {
			"type": "workflow",
			"name": "my-workflow",
			"limits": {
				"steps": 25000,
			},
			"schedules": ["0 * * * *"],
		},
	},
}
[exports.MyWorkflow]
type = "workflow"
name = "my-workflow"
schedules = [ "0 * * * *" ]

  [exports.MyWorkflow.limits]
  steps = 25_000

A workflow export accepts the same settings as a workflows binding: limits, schedules, and default_retention. When you run wrangler deploy, Wrangler creates or updates the Workflow with these settings.

You can declare a Workflow as both a binding and an export. Both declarations must use the same class, and cannot set the same setting to different values.

A workflows binding to a Workflow in another Worker cannot use the same name as a Workflow export in this Worker. Workflow names are unique per account.

Workflow exports require Wrangler 4.139.0 or above.

For more information, refer to Declare Workflows in exports.

Traffic Destination selector in Gateway policies

Gateway HTTP and Network policies now include a Traffic Destination selector that identifies how traffic exits Cloudflare. This allows administrators to write policies that target specific off-ramp methods - for example, applying different rules to traffic destined for the public Internet compared to traffic routed through Cloudflare Tunnel or Cloudflare WAN.

Available traffic destination values

UI name API value Description
Internet internet Traffic to the public Internet
Cloudflare WAN cloudflare_wan Traffic through a Cloudflare WAN connection
Cloudflare Tunnel cloudflare_tunnel Traffic to a private origin through Cloudflare Tunnel
Cloudflare One Client device_client Traffic to another device running the Cloudflare One Client
Mesh mesh Traffic through a Cloudflare Mesh node

The selector uses the net.offramp.type API field in both HTTP and Network policies.

UI name API example
Traffic Destination net.offramp.type == "internet"

For more information, refer to HTTP policies and Network policies.