# WAF Exceptions

**Web Application Firewall (WAF) Exceptions** are configurations that explicitly allow certain request patterns to bypass blocking, overriding the standard WAF security rules that would otherwise identify these requests as potentially malicious. They operate at a high level, analyzing specific components of HTTP requests, such as parameters (ARGS), request body contents (BODY), or the URL path (URL). Each exception is defined with a unique identifier, a match string, and an application zone, ensuring that the security filter remains effective while minimizing blocks on requests containing characteristics considered necessary or legitimate by the user, thus reducing false positives.

:::note
Exceptions were previously referred to as **Allowed Rules** in the Console interface. The API now uses the **Exceptions** terminology. Both terms refer to the same functionality.
:::

## Prerequisites

To instantiate **Custom Allowed Rules** in a **WAF Rule Set**, you must have an **Firewall** configuration with the **Web Application Firewall** module activated.

:::tip
Learn more about [Firewall modules](/en/documentation/products/secure/firewall/) and [Web Application Firewall](/en/documentation/products/secure/firewall/web-application-firewall/).
:::

## WAF Tuning
Azion's **WAF Tuning** feature is an analytical tool that allows you to identify blocks triggered by WAF rules based on traffic logs, enabling you to detect potential attacks and determine which cases can be allowed if they represent expected or accepted behavior. This resource allows users to adjust the WAF's precision to avoid false positives or permit legitimate traffic.

With WAF Tuning, you can analyze traffic distributed across network lists, IPs, and countries that correspond to your configured WAF rule sets.

For more information on how WAF tuning works in practice, [check our guide on how to configure it](https://www.azion.com/en/documentation/products/guides/secure/tune-waf/).

## When is it appropriate to use them?

WAF Custom Allowed Rules should be used with **caution** and only in specific situations, such as:
- Scenarios where false positives are impacting legitimate traffic, in the form of requests being responded to users with HTTP Status 400 or the response configured by the WAF.
- The need to allow requests from trusted partners or systems that use unconventional patterns.
- During testing and validation of new features in controlled environments.

:::caution[warning]
Ideally, these rules should be temporary and regularly reviewed to ensure they don't compromise application security. Since Allowed Rules are exemptions for characteristics considered bad practices in requests, they help guide development as a map of points to be improved in your application.
:::

## Best practices for using WAF Custom Allowed Rules

Companies can maintain an appropriate balance between security and functionality, minimizing potential risks associated with the incorrect use of WAF Custom Allowed Rules.

- **Minimization and specificity**: only allow what is necessary and be specific. Instead of broadly releasing many WAF rules, restrict them to the minimum viable and apply Allowed Rules only to the exact parts of the requests that are required.
- **Review and audit**: regularly evaluate WAF Custom Allowed Rules to ensure they are still necessary and appropriate, removing unnecessary or outdated entries. The WAF Tuning feature exists to assist in this process.
- **Testing and monitoring**: after implementing a WAF Custom Allowed Rule, perform rigorous testing to ensure no vulnerabilities are introduced. Monitor logs to identify anomalous behaviors or unauthorized access using [Real-Time Events](https://www.azion.com/en/products/real-time-events/) and [Data Stream](https://www.azion.com/en/products/data-stream/).
- **Environment segregation**: whenever possible, use different sets of WAF Custom Allowed Rules for development, testing, and production environments, adjusting permissions as needed for each context.
- **Documentation**: maintain clear documentation about the rules created and the reasoning behind each one to facilitate future reviews and audits.

## Security risks associated with the implementation of Web Application Firewall (WAF) Custom Allowed Rules

The incorrect use of WAF Custom Allowed Rules can expose web applications to significant risks. If too permissive or poorly configured, they can create security gaps that allow malicious traffic to enter, rendering security measures ineffective or reducing their impact. For example, by broadly allowing certain patterns or zones without careful analysis, malicious users can exploit these exceptions to inject code or execute brute force attacks.

## Practical example of a WAF Custom Allowed Rule in action

### Scenario

You have a web application protected by Azion's **Web Application Firewall (WAF)**. One of the WAF's default rules is blocking requests that contain special characters in the query string parameter, potentially indicating an SQL Injection attempt. However, you notice that a legitimate API in your application uses these special characters as part of its normal operation.

#### Problem

- The WAF is blocking legitimate API requests, generating **false positives**.
- Legitimate traffic is interrupted, negatively impacting the user experience.

#### Solution with WAF Custom Allowed Rule

1. Problem identification
- In **WAF Tuning**, you analyze blocked traffic logs and identify that legitimate requests are being blocked by the rule with the **Rule ID** corresponding to **SQL Injection**.
2. Creating an **Allowed Rule** to allow legitimate requests that meet specific criteria, such as the API path or query parameter.
3. Configuring the Allowed Rule:
- Go to the **Allowed Rules** tab in the WAF rule set.
- Click **+ Allowed Rule** and configure the following parameters:
  - **Rule ID**: choose the rule that's generating the false positive (for example, "SQL Injection").
  - **Path**: specify the API path that should be allowed (for example, `/api/v1/data`).
  - **Match Zone**: set to check only the query string.
  - **Regex**: enable if the allowed values contain specific patterns (for example, `^[a-zA-Z0-9]+$`).
  - **Status**: enable the rule.
4. Save the rule and test the application.
- Now, legitimate requests to `/api/v1/data` with special characters in the query string will be allowed, while other requests that violate the rule will continue to be blocked.

#### Result

The WAF continues to protect your application against SQL Injection attacks while now allowing legitimate traffic to the API. The user experience is restored, and application security is maintained.

## Practical example of an Allowed Rule

Consider that the API receives requests like this:

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

This request would be blocked by the **SQL Injection** rule due to the use of characters such as  `%` and `'`.  With the configured Allowed Rule, the WAF permits this request because it meets the defined criteria (path `/api/v1/data` and specific query string).

#### Benefits

- **Customization**: adjust the WAF to meet the specific needs of your application.
- **Reduced false positives**: allow legitimate traffic without compromising security.
- **Security maintenance**: requests that don’t meet the criteria of the Allowed Rule continue to be blocked.

## WAF internal rules

Your **WAF Custom Allowed Rules** can be based on actual requests that were marked by WAF as possible threats. You can also allow a custom rule in case of tests and false positives.

When creating custom allowed rules for a WAF configuration, it's necessary to choose between the available internal rules for its composition. 

See the list of all available internal rules below:

| Rule ID | Description                                                                                                                                |
|---------|--------------------------------------------------------------------------------------------------------------------------------------------|
| 1       | Weird request, unable to parse.                                                                                                            |
| 2       | Request larger than 128 kilobytes, stored on disk, and not parsed.                                                                         |
| 10      | Invalid HEX encoding (null bytes).                                                                                                         |
| 11      | Missing or unknown Content-Type header in a POST (this rule applies only to Request `Body` match zone).                                    |
| 12      | Invalid formatted URL.                                                                                                                     |
| 13      | Invalid POST format. <br/> **Note**: requests that fall under rule 13 will be blocked in some cases, even if the WAF is operating in *learning* mode. Read the [Rules Engine for Firewall](/en/documentation/products/secure/firewall/rules-engine/) documentation for the definition of learning/blocking modes. Read this guide [how to check your WAF mode](/en/documentation/products/guides/how-to-check-your-waf-mode/).                                                                                                                      |
| 14      | Invalid POST boundary.                                                                                                                     |
| 15      | Invalid JSON format.                                                                                                                       |
| 16      | POST with no body.                                                                                                                       |
| 17      | Possible SQL Injection attack: validation with `libinjection_sql`.                                                                         |
| 18      | Possible XSS attack: validation with `libinjection_xss`.                                                                                   |
| 1000    | Possible SQL Injection attack: SQL keywords found in `Body`, `Path`, `Query String`, or `Cookies`.                                         |
| 1001    | Possible SQL Injection or XSS attack: double quote `"` found in `Body`, `Path`, `Query String` or `Cookies`.                               |
| 1002    | Possible SQL Injection attack: possible hex encoding `0x` found in `Body`, `Path`, `Query String` or `Cookies`.                            |
| 1003    | Possible SQL Injection attack: MySQL comment `/*` found in `Body`, `Path`, `Query String` or `Cookies`.                                    |
| 1004    | Possible SQL Injection attack: MySQL comment `*/` found in `Body`, `Path`, `Query String` or `Cookies`.                                    |
| 1005    | Possible SQL Injection attack: MySQL keyword `\|` found in `Body`, `Path`, `Query String` or `Cookies`.                                    |
| 1006    | Possible SQL Injection attack: MySQL keyword `&&` found in `Body`, `Path`, `Query String` or `Cookies`.                                    |
| 1007    | Possible SQL Injection attack: MySQL comment `--` found in `Body`, `Path`, `Query String` or `Cookies`.                                    |
| 1008    | Possible SQL Injection or XSS attack: semicolon `;` found in `Body`, `Path` or `Query String`.                                             |
| 1009    | Possible SQL Injection attack: equal sign `=` found in `Body` or `Query String`.                                                           |
| 1010    | Possible SQL Injection or XSS attack: open parenthesis `(` found in `Body`, `Path`, `Query String` or `Cookies`.                           |
| 1011    | Possible SQL Injection or XSS attack: close parenthesis `)` found in `Body`, `Path`, `Query String` or `Cookies`.                          |
| 1013    | Possible SQL Injection or XSS attack: apostrophe `'` found in `Body`, `Path`, `Query String` or `Cookies`.                                 |
| 1015    | Possible SQL Injection attack: comma `,` found in `Body`, `Path`, `Query String` or `Cookies`.                                             |
| 1016    | Possible SQL Injection attack: MySQL comment `#` found in `Body`, `Path`, `Query String` or `Cookies`.                                     |
| 1017    | Possible SQL Injection attack: double at sign `@@` found in `Body`, `Path`, `Query String` or `Cookies`.                                   |
| 1100    | Possible RFI attack: scheme `http://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1101    | Possible RFI attack: scheme `https://` found in `Body`, `Query String` or `Cookies`.                                                       |
| 1102    | Possible RFI attack: scheme `ftp://` found in `Body`, `Query String` or `Cookies`.                                                         |
| 1103    | Possible RFI attack: scheme `php://` found in `Body`, `Query String` or `Cookies`.                                                         |
| 1104    | Possible RFI attack: scheme `sftp://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1105    | Possible RFI attack: scheme `zlib://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1106    | Possible RFI attack: scheme `data://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1107    | Possible RFI attack: scheme `glob://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1108    | Possible RFI attack: scheme `phar://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1109    | Possible RFI attack: scheme `file://` found in `Body`, `Query String` or `Cookies`.                                                        |
| 1110    | Possible RFI attack: scheme `gopher://` found in `Body`, `Query String` or `Cookies`.                                                      |
| 1200    | Possible Directory Traversal attack: double dot `..` found in `Body`, `Path`, `Query String` or `Cookies`.                                 |
| 1202    | Possible Directory Traversal attack: obvious probe `/etc/passwd` found in `Body`, `Path`, `Query String` or `Cookies`.                     |
| 1203    | Possible Directory Traversal attack: obvious Windows path `c:\\` found in `Body`, `Path`, `Query String` or `Cookies`.                     |
| 1204    | Possible Directory Traversal attack: obvious probe `cmd.exe` found in `Body`, `Path`, `Query String` or `Cookies`.                         |
| 1205    | Possible Directory Traversal attack: backslash `\` found in `Body`, `Path`, `Query String` or `Cookies`.                                   |
| 1207    | Possible Directory Traversal attack: obvious probe `/..;/)` found in `Query String` or `Path`.                                  |
| 1208    | Possible Directory Traversal attack: obvious probe `/.;/)` found in `Query String` or `Path`.                                   |
| 1209    | Possible Directory Traversal attack: obvious probe `/.%.2e/` found in `Query String` or `Path`.                                 |
| 1210    | Possible Directory Traversal attack: obvious probe `/%2e./` found in found in `Query String` or `Path`.                                 |
| 1302    | Possible XSS attack: HTML open tag `<` found in `Body`, `Path`, `Query String` or `Cookies`.                                               |
| 1303    | Possible XSS attack: HTML close tag `>` found in `Body`, `Path`, `Query String` or `Cookies`.                                              |
| 1310    | Possible XSS attack: open square bracket `[` found in `Body`, `Path`, `Query String` or `Cookies`.                                         |
| 1311    | Possible XSS attack: close square bracket `]` found in `Body`, `Path`, `Query String` or `Cookies`.                                        |
| 1312    | Possible XSS attack: tilde character `~` found in `Body`, `Path`, `Query String`, or `Cookies`.                                            |
| 1314    | Possible XSS attack: `` ` `` (*backtick*) found in `Body`, `Path`, `Query String`, or `Cookies`.                                    |

---

## Managing Exceptions via API

You can manage WAF Exceptions programmatically using the Azion API. This enables you to automate the creation, update, and deletion of exceptions, integrate WAF calibration into CI/CD pipelines, and build custom tools for managing your security posture.

### API endpoints

The Exceptions API provides the following operations:

| Operation | Endpoint | Description |
|-----------|----------|-------------|
| List | `GET /v4/edge_firewall/wafs/{waf_id}/exceptions` | List all exceptions for a WAF Rule Set |
| Create | `POST /v4/edge_firewall/wafs/{waf_id}/exceptions` | Create a new exception |
| Retrieve | `GET /v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id}` | Get details of a specific exception |
| Update | `PUT /v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id}` | Update an existing exception |
| Partial update | `PATCH /v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id}` | Update specific fields of an exception |
| Delete | `DELETE /v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id}` | Delete an exception |

For complete API specifications, refer to the [Azion API reference](https://api.azion.com/v4#/operations/list_waf_exceptions).

### Listing exceptions

To retrieve all exceptions configured for a WAF Rule Set:

```bash
curl --request GET \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

Response example:

```json
{
  "count": 2,
  "results": [
    {
      "id": 1234,
      "rule_id": 1000,
      "reason": "Allow legitimate API traffic",
      "match_zone": "query_string",
      "match_pattern": "^[a-zA-Z0-9]+$",
      "path": "/api/v1/data",
      "active": true
    },
    {
      "id": 5678,
      "rule_id": 1302,
      "reason": "Allow HTML in specific endpoint",
      "match_zone": "body",
      "match_pattern": "<script>",
      "path": "/api/v1/render",
      "active": true
    }
  ]
}
```

### Creating an exception

To create a new exception for a WAF Rule Set:

```bash
curl --request POST \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
    "rule_id": 1000,
    "reason": "Allow legitimate API traffic with SQL-like patterns",
    "match_zone": "query_string",
    "match_pattern": "^[a-zA-Z0-9\\s]+$",
    "path": "/api/v1/search",
    "active": true
  }'
```

### Retrieving a specific exception

To get details of a specific exception:

```bash
curl --request GET \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id} \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

### Updating an exception

To update all fields of an existing exception:

```bash
curl --request PUT \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id} \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
    "rule_id": 1000,
    "reason": "Updated reason for the exception",
    "match_zone": "query_string",
    "match_pattern": "^[a-zA-Z0-9\\s\\-]+$",
    "path": "/api/v1/search",
    "active": true
  }'
```

### Partially updating an exception

To update specific fields without modifying the entire exception:

```bash
curl --request PATCH \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id} \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
    "active": false,
    "reason": "Temporarily disabled for investigation"
  }'
```

### Deleting an exception

To delete an exception:

```bash
curl --request DELETE \
  --url https://api.azion.com/v4/edge_firewall/wafs/{waf_id}/exceptions/{exception_id} \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

### Exception object fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Unique identifier of the exception (read-only) |
| `rule_id` | integer | The WAF internal rule ID to create an exception for. See the [WAF internal rules table](#waf-internal-rules) for available IDs |
| `reason` | string | A description explaining why this exception was created |
| `match_zone` | string | The part of the request to match against. See [Match Zone options](/en/documentation/products/secure/firewall/web-application-firewall/#match-zone-dropdown-options) |
| `match_pattern` | string | The pattern to match in the specified zone |
| `path` | string | The URL path where the exception applies |
| `active` | boolean | Whether the exception is active (`true`) or inactive (`false`) |

:::tip
Use the API to automate WAF calibration workflows. For example, you can create a script that analyzes WAF Tuning data and automatically creates exceptions for verified false positives, or integrate exception management into your CI/CD pipeline to deploy security configurations alongside your application.
:::
| 1400    | Possible trick to evade protection: UTF7/8 encoding `&#` found in `Body`, `Path`, `Query String` or `Cookies`.                             |
| 1401    | Possible trick to evade protection: M$ encoding `%U` found in `Body`, `Path`, `Query String` or `Cookies`.                                 |
| 1500    | Possible File Upload attempt: `asp/php` or `.ph`, `.asp`, `.ht` found in filename in a multipart POST containing a file.                   |