Skip to main content

CHALLENGE SUSPICIOUS TRAFFIC WITH A CLOUDFLARE FIREWALL RULE

This guide shows you how to add a Cloudflare firewall rule that sends matching requests to a managed challenge, confirm the rule exists, and pause it later without deleting it.

Prerequisites

  • A Cloudflare API token with Firewall read and write permission for the zone, stored in a vault named cloudflare under the key CLOUDFLARE_API_TOKEN (see Storing Secrets)
  • The zone's ID, from the zone's overview page in the Cloudflare dashboard

Pull the extension

swamp extension pull @webframp/cloudflare

The output looks like:

INF extension·pull: Pulling "@webframp/cloudflare"@"2026.10.14.1"
INF extension·pull: Identity verified: "@webframp/cloudflare"@"2026.10.14.1"
INF extension·pull: Pulled "@webframp/cloudflare"@"2026.10.14.1"
INF extension·pull: Extracted 14 files:

Define the WAF behavior

Create a @webframp/cloudflare/waf behavior named cf-waf (see Create and Run a Behavior) with these global arguments:

globalArguments:
  apiToken: "${{ vault.get('cloudflare', 'CLOUDFLARE_API_TOKEN') }}"
  zoneId: "023e105f4ecef8ad9ca31a8372d0c353"

Create the rule

Pass the match condition as a Cloudflare rules expression. This example challenges requests for a login page:

swamp behavior run cf-waf create_rule \
  --input 'expression=http.request.uri.path contains "/wp-login.php"' \
  --input action=managed_challenge \
  --input 'description=Challenge login page requests'

This creates the rule on the zone and writes it to the rule resource.

To stop matching requests instead of challenging them, use action=block. To record matches without acting on them, use action=log. The optional priority input is a number, and paused is a boolean. Pass both with the :json= suffix, for example --input 'paused:json=true' to create the rule paused.

Confirm the rule and find its ID

swamp behavior run cf-waf list_rules

This fetches every firewall rule on the zone and writes the list to the rules resource. Copy the new rule's ID from it.

Pause the rule

Pause the rule when you want it to stop acting but want to keep its definition. Replace the ID with the one from list_rules:

swamp behavior run cf-waf toggle_rule \
  --input ruleId=372e67954025e0ba6aaa6d586b9e0b59 \
  --input 'paused:json=true'

This sets the rule to paused on Cloudflare and writes the updated rule to the rule resource. To turn the rule back on, run the same command with 'paused:json=false'. To remove the rule entirely, run delete_rule with the same ruleId.

Review the challenges issued

swamp behavior run cf-waf get_security_events \
  --input 'limit:json=20'

This fetches the 20 most recent security events for the zone, including blocks and challenges, and writes them to the events resource.

To put an approval step in front of rule changes, see Gate a Workflow with Manual Approval.