# Modes and levels

> The WAF mode decides whether detections block or are only recorded; the level decides how much evidence a request needs before it is blocked.

Two settings control the WAF of a site: `mode` and `waf_level`. Both can be set for the whole zone or for [one name](https://developers.openwaf.dev/rules/per-name-settings/).

## Modes

| `mode` | Dashboard | What happens |
|---|---|---|
| `active` (default) | Protect | Requests that reach the block threshold are blocked with a 403. Shields block. |
| `log` | Monitor only | Nothing is blocked by the WAF or the shields: each detection is recorded as a security event with action `log` and the request continues to the origin. |
| `off` | Off | No WAF inspection and no shields. The basic per-IP rate limit (`rate_limit_rpm`) is off too. |

The mode does not change IP and country rules, threat feeds, per-path rate limiting rules, rate limit rules or the access gate: they apply in every mode.

## Levels

OpenWAF runs OWASP CRS 4.25 at paranoia level 1. Every CRS rule that matches a request adds points to its **anomaly score** (critical 5, error 4, warning 3, notice 2). The level sets the score at which the request is blocked:

| `waf_level` | Dashboard | Blocks at a CRS score of | Typical use |
|---|---|---|---|
| `off` | Off — no WAF rules | — | Disable the WAF for the site, like `mode=off`. |
| `low` | Low | 15 | Only obvious attacks; fewest false positives. |
| `medium` (default) | Medium (recommended) | 10 | Balanced. |
| `high` | High | 5 | Strictest: a single critical match blocks. May block some legitimate requests. |

OpenWAF's own rules (ids 10000–19999, such as sensitive files, path traversal or request smuggling) describe unambiguous attacks: a critical one blocks at every level. Emergency virtual patches for new CVEs, such as rule 10075 for PHP2Shell, belong to this set.

> **Tip**
>
> When a legitimate request is blocked, add a [WAF exception](https://developers.openwaf.dev/waf/waf-exceptions/) for the rule that matched on that path. Lowering the level weakens the whole site.


## Application

`stack` describes the application behind the name: `generic` (default), `wordpress`, `nextjs` or `static`. Today only `wordpress` changes what the WAF does:

- it enables the [WordPress hardening shield](https://developers.openwaf.dev/waf/shields/#wordpress-hardening) (id 1001);
- OpenWAF rule 10002, which blocks WordPress paths (`/wp-login.php`, `/wp-admin`, `/wp-includes`, `/wp-content/uploads`, `/xmlrpc.php`) on sites that are **not** WordPress, no longer blocks.

`/wp-config.php` is blocked on every site, WordPress or not.

## Change them

**Dashboard**

Domain → **Security → Firewall → Protection**: **Mode**, **WAF sensitivity** and **Application**. Use **Applies to** to change one name only.
**CLI**

```sh
openwaf-cloud ctl zones set example.com mode=active waf_level=high stack=wordpress --reason "WordPress site, strict WAF"
```
**API**

```sh
curl -sS -X PATCH "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/edge" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: WordPress site, strict WAF" \
  -H "Content-Type: application/json" \
  -d '{"mode": "active", "waf_level": "high", "stack": "wordpress"}'
```
**MCP**

`update_settings` with `{"zone": "example.com", "settings": {"mode": "active", "waf_level": "high", "stack": "wordpress"}, "reason": "…"}`; simulate, then confirm.
