---
name: azion-create-a-waf-exception
description: >-
  Exempt one internal rule from scoring one part of a request, on the path that produces a false positive, from Azion Console, the CLI, or the API.
---

# Create a WAF exception

You can create a [Web Application Firewall (WAF)](/en/documentation/platform/firewall/#waf) exception from Azion Console, the Azion CLI, or the API. An exception takes one part of a request out of one internal rule's scoring, on the path you name. To turn many matched requests into exceptions at once instead, refer to [Tune a WAF rule set](/en/documentation/guides/application-security/firewall-and-waf/tune-waf/).

Azion Console calls an exception an allowed rule, and the tab that holds them reads **Allowed Rules**. The API and the Azion CLI call the same object an exception.

The example on this page clears one false positive. An API at `/api/v1/data` reads a `filter` query string parameter whose values carry an apostrophe:

```text
GET /api/v1/data?filter=name%20LIKE%20%27test%27
```

Internal rule `1013` matches that apostrophe and the request is refused. The exception below takes the `filter` parameter out of rule `1013` on that path alone, and leaves the rule scoring every other request.

---

Select the interface you will use. The prerequisites and every procedure below follow that choice.

## Prerequisites

- A firewall with the WAF module turned on. Refer to [Set a firewall's main settings](/en/documentation/guides/application-security/firewall-and-waf/firewall-configure-main-settings/).
- A rule set applied to the requests you want to exempt. Refer to [Create and apply a WAF rule set](/en/documentation/guides/application-security/firewall-and-waf/create-waf-rule-set/).
- The identifier of the internal rule that produced the false positive. For the identifiers and what each rule detects, refer to [WAF Rule Sets](/en/documentation/platform/firewall/waf/rules-set/#internal-rules).

**Console**

- Access to Azion Console. To sign in, refer to [How to access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

**CLI**

- The [Azion CLI](/en/documentation/devtools/cli/) installed and authorized.
- The id of the rule set that holds the exception.

**API**

- A personal token and `curl`. To create a token, refer to [Personal Tokens](/en/documentation/fundamentals/personal-tokens/).
- The id of the rule set that holds the exception.

---

## Create the exception

An exception names the internal rule it exempts, the path it is restricted to, and at least one condition naming the part of the request it covers. A condition built on a `specific_*` match zone carries the name or the value of one field; a generic match zone covers that part of every request. For every field an exception takes and all fifteen match zones, refer to [WAF Exceptions](/en/documentation/platform/firewall/waf/custom-allowed-rules/#fields).

The comparison is set once, for the whole exception. `contains` reads the path and the condition's name or value as substrings. `regex` reads both as regular expressions, and there is no way to make one a pattern and the other a literal.

**Console**

To create the exception in Azion Console:

1. **Open the WAF Rules page**

   Access [Azion Console](https://console.azion.com/) > **Edge Libraries** > **WAF Rules**.

2. **Select the rule set that scores the request**

3. **Select the Allowed Rules tab**

4. **Select + Allowed Rule**

5. **Select the rule to exempt**

   In **Rule ID**, select the rule that produced the false positive. For this example, rule `1013`.

6. **Record why the request is allowed**

   In **Description**, enter what the exception is for. For example: `Allow apostrophes in the data API filter`.

7. **Restrict the exception to one path**

   In **Path**, enter `/api/v1/data`.

8. **Name the part of the request**

   In **Condition**, select *Specific Query String Name* and enter `filter` in the **Name** field it reveals.

9. **Choose the comparison**

   In **Operator**, select `contains` to read the strings as substrings, or `regex` to read them as regular expressions.

10. **Save the exception**

The exception appears in the **Allowed Rules** tab, in a row carrying **Rule ID**, **Description**, **Path**, **Conditions**, **Status**, **Last Editor**, and **Last Modified**. The same tab carries a **Create from Tuning** button, which writes exceptions from records the rule set already matched.

**CLI**

The Azion CLI reads the exception from a file. The `--conditions` flag does not work on any value: the CLI sends an empty array and the API answers `400` with `10049 Ensure this field has at least 1 elements.`

To create the exception with the Azion CLI:

1. **Write the exception to a file**

   Save the following as `exception.json`:

   ```json
   {
     "rule_id": 1013,
     "name": "Allow apostrophes in the data API filter",
     "path": "/api/v1/data",
     "operator": "contains",
     "active": true,
     "conditions": [
       { "match": "specific_query_string_name", "name": "filter" }
     ]
   }
   ```

2. **Create the exception**

   Replace `<waf-id>` with the id of your rule set:

   ```bash
   azion create waf-exceptions --waf-id <waf-id> --file exception.json
   ```

3. **Read the output**

   The command prints the id of the new exception:

   ```text
   Created WAF Exception with ID 123457
   ```

Record that id. The next section passes it back to the CLI.

**API**

The exception is a `POST` to the `exceptions` collection of one rule set.

1. **Send the create request**

   Replace `<waf-id>` with the id of your rule set and `[TOKEN VALUE]` with your personal token:

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/wafs/<waf-id>/exceptions \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data '{
     "rule_id": 1013,
     "name": "Allow apostrophes in the data API filter",
     "path": "/api/v1/data",
     "operator": "contains",
     "active": true,
     "conditions": [
       { "match": "specific_query_string_name", "name": "filter" }
     ]
   }'
   ```

2. **Read the response**

   A create answers `202`, not `201`, and `"state": "pending"` means the change is still propagating:

   ```json
   {
     "state": "pending",
     "data": {
       "id": 123456,
       "rule_id": 1013,
       "name": "Allow apostrophes in the data API filter",
       "path": "/api/v1/data",
       "conditions": [
         { "match": "specific_query_string_name", "name": "filter" }
       ],
       "operator": "contains",
       "active": true,
       "last_editor": "user@example.com",
       "last_modified": "2026-01-01T12:00:00.000000Z"
     }
   }
   ```

Record the `id`. The next section reads the exception back with it. Of the six fields in the body, only `name` and `conditions` are required: `rule_id` defaults to `0`, which exempts every rule, `operator` defaults to `contains`, and `active` defaults to `true`.

An exception is accepted before it is in force. It reaches Azion's distributed infrastructure over the next few minutes, so a request that is still refused right after the create has broken nothing. Wait, then send it again.

---

## Confirm what the exception covers

> **Caution**
>
> A key the condition shape does not carry is dropped, not rejected. A condition sent as `{"match": "any_http_header_value", "name": "cookie"}` is accepted with `202` and reads back as `{"match": "any_http_header_value"}`. The exception then covers every request header instead of one, and nothing in the response says so.

Reading the exception back is the only way to catch that. Compare the `conditions` you get with the ones you sent, field by field.

**Console**

To read the exception back in Azion Console:

1. **Open the Allowed Rules tab of the rule set**
2. **Read the Conditions column of the row you created**

The column carries the match zone and, for a `specific_*` zone, the name or the value it applies to. A row whose match zone reads `Any` where you selected `Specific` covers that whole part of every request.

**CLI**

`azion describe waf-exceptions` prints the stored exception. Read it rather than `azion list waf-exceptions`, whose `RULE ID` column does not print the rule.

To read the exception back with the Azion CLI:

1. **Describe the exception**

   Replace `<waf-id>` and `<exception-id>` with your own ids:

   ```bash
   azion describe waf-exceptions --waf-id <waf-id> --exception-id <exception-id> --format json
   ```

2. **Compare the conditions with what you sent**

   ```json
   {"active": true, "conditions": [{"match": "specific_query_string_name", "name": "filter"}],
    "id": 123457, "last_editor": "user@example.com",
    "last_modified": "2026-01-01T12:00:00.000000Z", "name": "Allow apostrophes in the data API filter",
    "operator": "contains", "path": "/api/v1/data", "rule_id": 1013}
   ```

The stored condition carries the `name` key. An exception whose stored condition holds `match` alone covers every query string parameter.

**API**

To read the exception back from the API:

1. **Send the read request**

   Replace `<waf-id>` and `<exception-id>` with your own ids:

   ```bash
   curl --request GET \
     --url https://api.azion.com/v4/workspace/wafs/<waf-id>/exceptions/<exception-id> \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]'
   ```

2. **Compare the conditions with what you sent**

   A read answers `200` and carries the stored exception:

   ```json
   {
     "data": {
       "id": 123456,
       "rule_id": 1013,
       "name": "Allow apostrophes in the data API filter",
       "path": "/api/v1/data",
       "conditions": [
         { "match": "specific_query_string_name", "name": "filter" }
       ],
       "operator": "contains",
       "active": true,
       "last_editor": "user@example.com",
       "last_modified": "2026-01-01T12:00:00.000000Z"
     }
   }
   ```

The stored condition carries the `name` key. An exception whose stored condition holds `match` alone covers every query string parameter.

---

## Next steps

- [WAF Exceptions](/en/documentation/platform/firewall/waf/custom-allowed-rules.md): Every field an exception carries, all fifteen match zones, and the Tuning screen.
- [Tune a WAF rule set](/en/documentation/guides/application-security/firewall-and-waf/tune-waf.md): Read what a rule set matched and write exceptions from those records in bulk.
- [Scoring and modes](/en/documentation/platform/firewall/waf/scoring-and-modes.md#exceptions): What an exception subtracts from scoring, and what a wide one costs.
- [Firewall best practices](/en/documentation/platform/firewall/best-practices.md#waf): How to keep an exception narrow and how to decide when to remove it.
