Zero Trust has significantly upgraded its Shadow IT analytics, providing you with unprecedented visibility into your organizations use of SaaS tools. With this dashboard, you can review who is using an application and volumes of data transfer to the application.
You can review these metrics against application type, such as Artificial Intelligence or Social Media. You can also mark applications with an approval status, including Unreviewed, In Review, Approved, and Unapproved designating how they can be used in your organization.
These application statuses can also be used in Gateway HTTP policies, so you can block, isolate, limit uploads and downloads, and more based on the application status.
Both the analytics and policies are accessible in the Cloudflare Zero Trust dashboard ↗︎, empowering organizations with better visibility and control.
Cloudflare CASB ↗︎ now supports three of the most widely used GenAI platforms — OpenAI ChatGPT, Anthropic Claude, and Google Gemini. These API-based integrations give security teams agentless visibility into posture, data, and compliance risks across their organization’s use of generative AI.
Key capabilities
Agentless connections — connect ChatGPT, Claude, and Gemini tenants via API; no endpoint software required
Posture management — detect insecure settings and misconfigurations that could lead to data exposure
DLP detection — identify sensitive data in uploaded chat attachments or files
GenAI-specific insights — surface risks unique to each provider’s capabilities
You can now control who within your organization has access to internal MCP servers, by putting internal MCP servers behind Cloudflare Access.
Self-hosted applications in Cloudflare Access now support OAuth for MCP server authentication. This allows Cloudflare to delegate access from any self-hosted application to an MCP server via OAuth. The OAuth access token authorizes the MCP server to make requests to your self-hosted applications on behalf of the authorized user, using that user's specific permissions and scopes.
For example, if you have an MCP server designed for internal use within your organization, you can configure Access policies to ensure that only authorized users can access it, regardless of which MCP client they use. Support for internal, self-hosted MCP servers also works with MCP server portals, allowing you to provide a single MCP endpoint for multiple MCP servers. For more on MCP server portals, read the blog post ↗︎ on the Cloudflare Blog.
An MCP server portal centralizes multiple Model Context Protocol (MCP) servers onto a single HTTP endpoint. Key benefits include:
Streamlined access to multiple MCP servers: MCP server portals support both unauthenticated MCP servers as well as MCP servers secured using any third-party or custom OAuth provider. Users log in to the portal URL through Cloudflare Access and are prompted to authenticate separately to each server that requires OAuth.
Customized tools per portal: Admins can tailor an MCP portal to a particular use case by choosing the specific tools and prompt templates that they want to make available to users through the portal. This allows users to access a curated set of tools and prompts — the less external context exposed to the AI model, the better the AI responses tend to be.
Observability: Once the user's AI agent is connected to the portal, Cloudflare Access logs the individual requests made using the tools in the portal.
This is available in an open beta for all customers across all plans! For more information check out our blog ↗︎ for this release.
You now have access to a comprehensive suite of capabilities to secure your organization's use of generative AI. AI prompt protection introduces four key features that work together to provide deep visibility and granular control.
Prompt Detection for AI Applications
DLP can now natively detect and inspect user prompts submitted to popular AI applications, including Google Gemini, ChatGPT, Claude, and Perplexity.
Prompt Analysis and Topic Classification
Our DLP engine performs deep analysis on each prompt, applying topic classification. These topics are grouped into two evaluation categories:
Content: PII, Source Code, Credentials and Secrets, Financial Information, and Customer Data.
Intent: Jailbreak attempts, requests for malicious code, or attempts to extract PII.
To help you apply these topics quickly, we have also released five new predefined profiles (for example, AI Prompt: AI Security, AI Prompt: PII) that bundle these new topics.
Granular Guardrails
You can now build guardrails using Gateway HTTP policies with application granular controls. Apply a DLP profile containing an AI prompt topic detection to individual AI applications (for example, ChatGPT) and specific user actions (for example, SendPrompt) to block sensitive prompts.
Full Prompt Logging
To aid in incident investigation, an optional setting in your Gateway policy allows you to capture prompt logs to store the full interaction of prompts that trigger a policy match. To make investigations easier, logs can be filtered by conversation_id, allowing you to reconstruct the full context of an interaction that led to a policy violation.
AI prompt protection is now available in open beta. To learn more about it, read the blog ↗︎ or refer to AI prompt topics.
JavaScript asset responses have been updated to use the text/javascript Content-Type header instead of application/javascript. While both MIME types are widely supported by browsers, the HTML Living Standard explicitly recommends text/javascript as the preferred type going forward.
This change improves:
Standards alignment: Ensures consistency with the HTML spec and modern web platform guidance.
Interoperability: Some developer tools, validators, and proxies expect text/javascript and may warn or behave inconsistently with application/javascript.
Future-proofing: By following the spec-preferred MIME type, we reduce the risk of deprecation warnings or unexpected behavior in evolving browser environments.
Consistency: Most frameworks, CDNs, and hosting providers now default to text/javascript, so this change matches common ecosystem practice.
Because all major browsers accept both MIME types, this update is backwards compatible and should not cause breakage.
Users will see this change on the next deployment of their assets.
Enterprise Gateway users can now use Bring Your Own IP (BYOIP) for dedicated egress IPs.
Admins can now onboard and use their own IPv4 or IPv6 prefixes to egress traffic from Cloudflare, delivering greater control, flexibility, and compliance for network traffic.
Get started by following the BYOIP onboarding process. Once your IPs are onboarded, go to Gateway > Egress policies and select or create an egress policy. In Select an egress IP, choose Use dedicated egress IPs (Cloudflare or BYOIP), then select your BYOIP address from the dropdown menu.
Wrangler's error screen has received several improvements to enhance your debugging experience!
The error screen now features a refreshed design thanks to youch ↗︎, with support for both light and dark themes, improved source map resolution logic that handles missing source files more reliably, and better error cause display.
Before
After (Light)
After (Dark)
Try it out now with npx wrangler@latest dev in your Workers project.
You can now create more granular, network-aware Custom Rules in Cloudflare Load Balancing using the Autonomous System Number (ASN) of an incoming request.
This allows you to steer traffic with greater precision based on the network source of a request. For example, you can route traffic from specific Internet Service Providers (ISPs) or enterprise customers to dedicated infrastructure, optimize performance, or enforce compliance by directing certain networks to preferred data centers.
To get started, create a Custom Rule ↗︎ in your Load Balancer and select AS Num from the Field dropdown.
The node:fs module provides access to a virtual file system in Workers. You can use it to read and write files, create directories, and perform other file system operations.
The virtual file system is ephemeral with each individual request havig its own isolated temporary file space. Files written to the file system will not persist across requests and will not be shared across requests or across different Workers.
Workers running with the nodejs_compat compatibility flag will have access to the node:fs module by default when the compatibility date is set to 2025-09-01 or later. Support for the API can also be enabled using the enable_nodejs_fs_module compatibility flag together with the nodejs_compat flag. The node:fs module can be disabled using the disable_nodejs_fs_module compatibility flag.
import fs from "node:fs";const config = JSON.parse(fs.readFileSync("/bundle/config.json", "utf-8"));export default { async fetch(request) { return new Response(`Config value: ${config.value}`); },};
There are a number of initial limitations to the node:fs implementation:
The glob APIs (e.g. fs.globSync(...)) are not implemented.
The file watching APIs (e.g. fs.watch(...)) are not implemented.
The file timestamps (modified time, access time, etc) are only partially supported. For now, these will always return the Unix epoch.
The Web File System API provides access to the same virtual file system as the node:fs module, but with a different API surface. The Web File System API is only available in Workers running with the enable_web_file_system compatibility flag. The nodejs_compat compatibility flag is not required to use the Web File System API.
As there are still some parts of the Web File System API that are not fully standardized, there may be some differences between the Workers implementation and the implementations in browsers.
If you're serving Static Assets with a _redirects file containing a rule like /ja/* /:splat, paths with double slashes were previously misinterpreted as external URLs. For example, visiting /ja//example.com would incorrectly redirect to https://example.com instead of /example.com on your domain. This has been fixed and double slashes now correctly resolve as local paths. Note: Cloudflare Pages was not affected by this issue.
We've updated preview URLs for Cloudflare Workers to support long branch names.
Previously, branch and Worker names exceeding the 63-character DNS limit would cause alias generation to fail, leaving pull requests without aliased preview URLs. This particularly impacted teams relying on descriptive branch naming.
Now, Cloudflare automatically truncates long branch names and appends a unique hash, ensuring every pull request gets a working preview link.
How it works
63 characters or less: <branch-name>-<worker-name> → Uses actual branch name as is
64 characters or more: <truncated-branch-name>--<hash>-<worker-name> → Uses truncated name with 4-character hash
Hash generation: The hash is derived from the full branch name to ensure uniqueness
Stable URLs: The same branch always generates the same hash across all commits
Requirements and compatibility
Wrangler 4.30.0 or later: This feature requires updating to wrangler@4.30.0+
No configuration needed: Works automatically with existing preview URL setups
Cloudflare Access logs now support the Customer Metadata Boundary (CMB). If you have configured the CMB for your account, all Access logging will respect that configuration.
We are changing how Python Workers are structured by default. Previously, handlers were defined at the top-level of a module as on_fetch, on_scheduled, etc. methods, but now they live in an entrypoint class.
Here's an example of how to now define a Worker with a fetch handler:
Resolved several issues with the cloudflare_workers_script resource that resulted in unwarranted plan diffs, including:
Using Durable Objects migrations
Using some bindings such as secret_text
Using smart placement
A resource should never show a plan diff if there isn't an actual change. This fix reduces unnecessary noise in your Terraform plan and is available in Cloudflare Terraform Provider 5.8.0.
Improved File Management
You can now specify content_file and content_sha256 instead of content. This prevents the Workers script content from being stored in the state file which greatly reduces plan diff size and noise. If your workflow synced plans remotely, this should now happen much faster since there is less data to sync. This is available in Cloudflare Terraform Provider 5.7.0.
Fixed an issue where Workers script versions in the SDK did not allow uploading files. This now works, and also has an improved files upload interface:
A minimal implementation of the MessageChannel API ↗︎ is now available in Workers. This means that you can use MessageChannel to send messages between different parts of your Worker, but not across different Workers.
The MessageChannel and MessagePort APIs will be available by default at the global scope
with any worker using a compatibility date of 2025-08-15 or later. It is also available
using the expose_global_message_channel compatibility flag, or can be explicitly disabled
using the no_expose_global_message_channel compatibility flag.
const { port1, port2 } = new MessageChannel();port2.onmessage = (event) => { console.log('Received message:', event.data);};port2.postMessage('Hello from port2!');
Any value that can be used with the structuredClone(...) API can be sent over the port.
Differences
There are a number of key limitations to the MessageChannel API in Workers:
Transfer lists are currently not supported. This means that you will not be able to transfer
ownership of objects like ArrayBuffer or MessagePort between ports.
The MessagePort is not yet serializable. This means that you cannot send a MessagePort object
through the postMessage method or via JSRPC calls.
The 'messageerror' event is only partially supported. If the 'onmessage' handler throws an
error, the 'messageerror' event will be triggered, however, it will not be triggered when there
are errors serializing or deserializing the message data. Instead, the error will be thrown when
the postMessage method is called on the sending port.
The 'close' event will be emitted on both ports when one of the ports is closed, however it
will not be emitted when the Worker is terminated or when one of the ports is garbage collected.
Now, you can use .env files to provide secrets and override environment variables on the env object during local development with Wrangler and the Cloudflare Vite plugin.
Previously in local development, if you wanted to provide secrets or environment variables during local development, you had to use .dev.vars files.
This is still supported, but you can now also use .env files, which are more familiar to many developers.
Using .env files in local development
You can create a .env file in your project root to define environment variables that will be used when running wrangler dev or vite dev. The .env file should be formatted like a dotenv file, such as KEY="VALUE":
.envbash
TITLE="My Worker"API_TOKEN="dev-token"
When you run wrangler dev or vite dev, the environment variables defined in the .env file will be available in your Worker code via the env object:
If your Worker defines multiple environments, you can set different variables for each environment (ex: production or staging) by creating files named .env.<environment-name>.
When you use wrangler <command> --env <environment-name> or CLOUDFLARE_ENV=<environment-name> vite dev, the corresponding environment-specific file will also be loaded and merged with the .env file.
For example, if you want to set different environment variables for the staging environment, you can create a file named .env.staging:
.env.stagingbash
API_TOKEN="staging-token"
When you run wrangler dev --env staging or CLOUDFLARE_ENV=staging vite dev, the environment variables from .env.staging will be merged onto those from .env.
export default { async fetch(request, env) { const title = env.TITLE; // "My Worker" (from `.env`) const apiToken = env.API_TOKEN; // "staging-token" (from `.env.staging`, overriding the value from `.env`) const response = await fetch( `https://api.example.com/data?token=${apiToken}`, ); return new Response(`Title: ${title} - ` + (await response.text())); },};
Find out more
For more information on how to use .env files with Wrangler and the Cloudflare Vite plugin, see the following documentation:
New information about broadcast metrics and events is now available in
Cloudflare Stream in the Live Input details of the Dashboard.
You can now easily understand broadcast-side health and performance with new
observability, which can help when troubleshooting common issues, particularly
for new customers who are just getting started, and platform customers who may
have limited visibility into how their end-users configure their encoders.
To get started, start a live stream (just getting started?), then visit the Live Input details page in Dash.
See our new live Troubleshooting guide
to learn what these metrics mean and how to use them to address common broadcast
issues.
You can now import waitUntil from cloudflare:workers to extend your Worker's execution beyond the request lifecycle from anywhere in your code.
Previously, waitUntil could only be accessed through the execution context (ctx) parameter passed to your Worker's handler functions. This meant that if you needed to schedule background tasks from deeply nested functions or utility modules, you had to pass the ctx object through multiple function calls to access waitUntil.
Now, you can import waitUntil directly and use it anywhere in your Worker without needing to pass ctx as a parameter:
import { waitUntil } from "cloudflare:workers";export function trackAnalytics(eventData) { const analyticsPromise = fetch("https://analytics.example.com/track", { method: "POST", body: JSON.stringify(eventData), }); // Extend execution to ensure analytics tracking completes waitUntil(analyticsPromise);}
This is particularly useful when you want to:
Schedule background tasks from utility functions or modules
Extend execution for analytics, logging, or cleanup operations
Avoid passing the execution context through multiple layers of function calls
import { waitUntil } from "cloudflare:workers";export default { async fetch(request, env, ctx) { // Background task that should complete even after response is sent cleanupTempData(env.KV_NAMESPACE); return new Response("Hello, World!"); }};function cleanupTempData(kvNamespace) { // This function can now use waitUntil without needing ctx const deletePromise = kvNamespace.delete("temp-key"); waitUntil(deletePromise);}
When you deploy MX or Inline, not only can you apply email link isolation to suspicious links in all emails (including benign), you can now also apply email link isolation to all links of a specified disposition. This provides more flexibility in controlling user actions within emails.
For example, you may want to deliver suspicious messages but isolate the links found within them so that users who choose to interact with the links will not accidentally expose your organization to threats. This means your end users are more secure than ever before.
To isolate all links within a message based on the disposition, select Settings > Link Actions > View and select Configure. As with other other links you isolate, an interstitial will be provided to warn users that this site has been isolated and the link will be recrawled live to evaluate if there are any changes in our threat intel. Learn more about this feature on Configure link actions ↗︎.
This feature is available across these Email security packages:
By setting the value of the cache property to no-cache, you can force Cloudflare's
cache to revalidate its contents with the origin when
making subrequests from Cloudflare Workers.
When no-cache is set, the Worker request will first look for a match in Cloudflare's cache, then:
If there is a match, a conditional request is sent to the origin, regardless of whether or not the match is fresh or stale. If the resource has not changed, the
cached version is returned. If the resource has changed, it will be downloaded from the origin, updated in the cache, and returned.
If there is no match, Workers will make a standard request to the origin and cache the response.
This increases compatibility with NPM packages and JavaScript frameworks that rely on setting the
cache property, which is a cross-platform standard part
of the Request interface. Previously, if you set the cache
property on Request to 'no-cache', the Workers runtime threw an exception.
Cloudflare Load Balancing Monitors support loading and applying settings for a specific zone to monitoring requests to origin endpoints. This feature has been migrated to new infrastructure to improve reliability, performance, and accuracy.
All zone monitors have been tested against the new infrastructure. There should be no change to health monitoring results of currently healthy and active pools. Newly created or re-enabled pools may need validation of their monitor zone settings before being introduced to service, especially regarding correct application of mTLS.
What you can expect:
More reliable application of zone settings to monitoring requests, including
Authenticated Origin Pulls
Aegis Egress IP Pools
Argo Smart Routing
HTTP/2 to Origin
Improved support and bug fixes for retries, redirects, and proxied origin resolution
Improved performance and reliability of monitoring requests within the Cloudflare network
Unrelated CDN or WAF configuration changes should have no risk of impact to pool health
As part of the ongoing open beta for Workers Builds, we’ve increased the available disk space for builds from 8 GB to 20 GB for both Free and Paid plans.
This provides more space for larger projects, dependencies, and build artifacts while improving overall build reliability.
Metric
Free Plan
Paid Plans
Disk Space
20 GB
20 GB
All other build limits — including CPU, memory, build minutes, and timeout remain unchanged.
You can now configure and run Containers alongside your Worker during local development when using the Cloudflare Vite plugin. Previously, you could only develop locally when using Wrangler as your local development server.
Configuration
You can simply configure your Worker and your Container(s) in your Wrangler configuration file:
Once your Worker and Containers are configured, you can access the Container instances from your Worker code:
import { Container, getContainer } from "@cloudflare/containers";export class MyContainer extends Container { defaultPort = 4000; // Port the container is listening on sleepAfter = "10m"; // Stop the instance if requests not sent for 10 minutes}async fetch(request, env) { const { "session-id": sessionId } = await request.json(); // Get the container instance for the given session ID const containerInstance = getContainer(env.MY_CONTAINER, sessionId) // Pass the request to the container instance on its default port return containerInstance.fetch(request);}
Local development
To develop your Worker locally, start a local dev server by running