
"Programmable" has become a loose word
In cloud security marketing, almost everything gets called programmable. A vendor ships a public API, a Terraform provider, a webhook for alerts, and suddenly the product is "programmable security." Those are real conveniences — they let you automate configuration or react to events after the fact. But none of them let your own logic participate in the moment a security decision is actually made. An API call happens before or after enforcement; a webhook fires once something has already been decided. Cloudflare’s argument is that none of this counts as true programmability, because the policy engine itself still only understands a fixed menu of conditions and actions. True programmability, in this framing, means the gateway can pause mid-evaluation, hand control to a small piece of customer-written code, and use whatever that code returns to help decide what happens next.
This distinction matters because of a trade-off that has shaped network security for years: run your own detection stack and get maximum flexibility at the cost of constant maintenance, or adopt a vendor’s gateway and get low maintenance at the cost of flexibility. Teams that hit the ceiling of a rigid policy engine tend to resolve it the same way — they bolt on more infrastructure. A pool of NGINX proxies just to inject a header derived from a login token. A Logpush-to-SIEM-to-Slack pipeline, with a built-in delay of minutes, just to get a notification when an employee signs up for a new SaaS tool. Each workaround is a small, separate system that now needs patching, monitoring, and someone responsible for keeping it alive indefinitely.
Where the new logic actually sits
The core design choice is that the custom code doesn’t sit beside the gateway — it sits inside its traffic path, on the same machines, because Cloudflare’s edge-compute product (Workers) and its gateway (Gateway) already run across the same distributed network.
flowchart TD A[User request] --> B[Gateway policy check] B --> C[Custom Function: Worker returns a value] C --> B B --> D[Action selected] D --> E[Forward action: Worker transforms traffic] E --> F[Origin server] F --> G[Response to user]
That loop back into the policy check is the crux of it: instead of the gateway sending traffic out to some external automation and waiting, it makes what amounts to a local function call to a Worker and keeps going.
Two different jobs, not one feature
Cloudflare actually ships two distinct mechanisms, and conflating them is the easiest way to misunderstand what’s new. A custom function is a short-lived calculation: the Worker receives context about a request (identity, device posture, headers) and returns a single typed value — a string, number, or boolean — that the gateway can then use inside a normal rule condition, the same way it already uses "source IP" or "content category." The Forward action is a different animal: it’s a full inline proxy step, where a Worker can read and rewrite the request and the response before it reaches the origin.
| Mechanism | Purpose | When it runs | Input | Output / best fit |
|---|---|---|---|---|
| Static policy rule | Match a known condition | During evaluation | Built-in selectors (IP, category, port) | Simple allow/block/log cases |
| Custom Function | Evaluate custom logic as a condition | Inline, mid-evaluation | Request/identity/device context | A typed value (e.g. a JWT-derived role) used in a rule |
| Forward action | Transform or proxy live traffic | After a match, before/after origin | Full headers and body | Header injection, interstitial pages, async alerts |
A custom function answers a question; a Forward action changes the traffic itself. Using a Worker as a judgment call is very different from using one as a transformation layer, and the two can be combined — a function can decide that a request is risky, and a Forward action can decide what happens to it next, such as serving a justification page or injecting an audit header instead of standing up a dedicated proxy fleet.
The same pattern shows up in data-loss prevention
Cloudflare extends the same idea to DLP: rather than only matching data against regexes or word lists, a custom validation function can call out — say, to check whether a detected API key is actually still active — before the policy engine decides whether to enforce anything. The pattern is identical to the gateway case: policy matching narrows the field, and customer logic adds the context a generic pattern-matcher can’t have.
What this does and doesn’t settle
This is a useful illustration of a broader shift in cloud platforms: moving from shipping fixed features toward exposing a programmable control plane that customers extend themselves. But a few things are worth keeping in perspective. Co-locating compute and enforcement avoids an extra network hop, not every source of latency — a slow or poorly written Worker still adds its own execution time. The Forward action is in public beta, and Custom Functions are not yet generally available, so the simplification promised here is still mostly a design claim rather than a track record. And putting customer-written code inside the enforcement path is not risk-free: a bug, timeout, or unexpected return value in that code now has to be planned for with explicit fallback behavior, because it directly shapes a security decision rather than sitting safely outside it.
The real lesson isn’t that one vendor added a clever feature. It’s that programmability in security only means something when custom logic can act during enforcement, not just around it — everything else is orchestration wearing a programmable label.


