---
title: chaitin-waf
keywords:
  - Apache APISIX
  - API Gateway
  - Plugin
  - WAF
description: The chaitin-waf Plugin integrates with Chaitin WAF (SafeLine) to detect and block web threats, strengthening API security and protecting user data.
---

<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->

<head>
  <link rel="canonical" href="https://docs.api7.ai/hub/chaitin-waf" />
</head>

## Description

The `chaitin-waf` Plugin integrates with the Chaitin WAF (SafeLine) service to provide advanced detection and prevention of web-based threats, enhancing application security and protecting sensitive user data.

## Response Headers

The Plugin can add the following response headers, depending on the configuration of `append_waf_resp_header` and `append_waf_debug_header`:

| Header | Description |
|--------|-------------|
| `X-APISIX-CHAITIN-WAF` | Indicates whether APISIX forwarded the request to the WAF server.<br />• `yes`: Request was forwarded to the WAF server.<br />• `no`: Request was not forwarded to the WAF server.<br />• `unhealthy`: Request matches the configured rules, but no WAF service is available.<br />• `err`: An error occurred during Plugin execution. The `X-APISIX-CHAITIN-WAF-ERROR` header is also included with details.<br />• `waf-err`: Error while interacting with the WAF server. The `X-APISIX-CHAITIN-WAF-ERROR` header is also included with details.<br />• `timeout`: Request to the WAF server timed out. |
| `X-APISIX-CHAITIN-WAF-TIME` | Round-trip time (RTT) in milliseconds for the request to the Chaitin WAF server, including both network latency and WAF server processing. |
| `X-APISIX-CHAITIN-WAF-STATUS` | Status code returned to APISIX by the WAF server. |
| `X-APISIX-CHAITIN-WAF-ACTION` | Action returned to APISIX by the WAF server.<br />• `pass`: Request was allowed by the WAF service.<br />• `reject`: Request was blocked by the WAF service. |
| `X-APISIX-CHAITIN-WAF-ERROR` | Debug header. Contains WAF error message. |
| `X-APISIX-CHAITIN-WAF-SERVER` | Debug header. Indicates which WAF server was selected. |

## Attributes

| Name                     | Type          | Required | Default | Valid values             | Description |
|--------------------------|---------------|----------|---------|--------------------------|-------------|
| mode                     | string        | false    | block   | `off`, `monitor`, `block`| Mode to determine how the Plugin behaves for matched requests. In `off` mode, WAF checks are skipped. In `monitor` mode, requests with potential threats are logged but not blocked. In `block` mode, requests with threats are blocked as determined by the WAF service. |
| match                    | array[object] | false    |         |                          | An array of matching rules. The Plugin uses these rules to decide whether to perform a WAF check on a request. If the list is empty, all requests are processed. |
| match.vars               | array[array]  | false    |         |                          | An array of one or more matching conditions in the form of [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) to conditionally execute the plugin. |
| append_waf_resp_header   | boolean       | false    | true    |                          | If true, add response headers `X-APISIX-CHAITIN-WAF`, `X-APISIX-CHAITIN-WAF-TIME`, `X-APISIX-CHAITIN-WAF-ACTION`, and `X-APISIX-CHAITIN-WAF-STATUS`. |
| append_waf_debug_header  | boolean       | false    | false   |                          | If true, add debugging headers `X-APISIX-CHAITIN-WAF-ERROR` and `X-APISIX-CHAITIN-WAF-SERVER` to the response. Effective only when `append_waf_resp_header` is `true`. |
| config                   | object        | false    |         |                          | Chaitin WAF service configurations. These settings override the corresponding metadata defaults when specified. |
| config.connect_timeout   | integer       | false    | 1000    |                          | The connection timeout to the WAF service, in milliseconds. |
| config.send_timeout      | integer       | false    | 1000    |                          | The sending timeout for transmitting data to the WAF service, in milliseconds. |
| config.read_timeout      | integer       | false    | 1000    |                          | The reading timeout for receiving data from the WAF service, in milliseconds. |
| config.req_body_size     | integer       | false    | 1024    |                          | The maximum allowed request body size, in KB. |
| config.keepalive_size    | integer       | false    | 256     |                          | The maximum number of idle connections to the WAF detection service that can be maintained concurrently. |
| config.keepalive_timeout | integer       | false    | 60000   |                          | The idle connection timeout for the WAF service, in milliseconds. |
| config.real_client_ip    | boolean       | false    | true    |                          | If true, the client IP is obtained from the `X-Forwarded-For` header. If false, the Plugin uses the client IP from the connection. |

## Plugin Metadata

| Name                     | Type          | Required | Default | Valid values | Description |
|--------------------------|---------------|----------|---------|--------------|-------------|
| nodes                    | array[object] | True     |         |              | An array of addresses for the Chaitin WAF service. |
| nodes.host               | string        | True     |         |              | Address of Chaitin WAF service. Supports IPv4, IPv6, Unix Socket, etc. |
| nodes.port               | integer       | False    | 80      |              | Port of Chaitin WAF service. |
| mode                     | string        | False    |         |    block     | Mode to determine how the Plugin behaves for matched requests. In `off` mode, WAF checks are skipped. In `monitor` mode, requests with potential threats are logged but not blocked. In `block` mode, requests with threats are blocked as determined by the WAF service. |
| config                   | object        | False    |         |              | Chaitin WAF service configurations. |
| config.connect_timeout   | integer       | False    | 1000    |              | The connection timeout to the WAF service, in milliseconds. |
| config.send_timeout      | integer       | False    | 1000    |              | The sending timeout for transmitting data to the WAF service, in milliseconds. |
| config.read_timeout      | integer       | False    | 1000    |              | The reading timeout for receiving data from the WAF service, in milliseconds. |
| config.req_body_size     | integer       | False    | 1024    |              | The maximum allowed request body size, in KB. |
| config.keepalive_size    | integer       | False    | 256     |              | The maximum number of idle connections to the WAF detection service that can be maintained concurrently. |
| config.keepalive_timeout | integer       | False    | 60000   |              | The idle connection timeout for the WAF service, in milliseconds. |
| config.real_client_ip    | boolean       | False    | true    |              | If true, the client IP is obtained from the `X-Forwarded-For` header. If false, the Plugin uses the client IP from the connection. |

## Examples

The examples below demonstrate how you can configure chaitin-waf Plugin for different scenarios.

Before proceeding, make sure you have installed [Chaitin WAF (SafeLine)](https://docs.waf.chaitin.com/en/GetStarted/Deploy).

:::note
Only `X-Forwarded-*` headers sent from addresses in the `apisix.trusted_addresses` configuration (supports IP and CIDR) will be trusted and passed to plugins or upstream. If `apisix.trusted_addresses` is not configured or the IP is not within the configured address range, all `X-Forwarded-*` headers will be overridden with trusted values.
:::

:::note
You can fetch the `admin_key` from `config.yaml` and save to an environment variable with the following command:

```bash
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
```

:::

### Block Malicious Requests on a Route

The following example demonstrates how to integrate with Chaitin WAF to protect traffic on a route, rejecting malicious requests immediately.

Configure the Chaitin WAF connection details using Plugin Metadata (update the address accordingly):

```shell
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
  -H 'X-API-KEY: ${admin_key}' \
  -d '{
    "nodes": [
      {
        "host": "172.22.222.5",
        "port": 8000
      }
    ]
  }'
```

Create a Route and enable `chaitin-waf` on the Route to block requests identified to be malicious:

```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "chaitin-waf-route",
    "uri": "/anything",
    "plugins": {
      "chaitin-waf": {
        "mode": "block",
        "append_waf_resp_header": true,
        "append_waf_debug_header": true
      }
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org:80": 1
      }
    }
  }'
```

Send a standard request to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything"
```

You should receive an `HTTP/1.1 200 OK` response.

Send a request with SQL injection to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
```

You should see an `HTTP/1.1 403 Forbidden` response similar to the following:

```text
...
X-APISIX-CHAITIN-WAF-STATUS: 403
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF-SERVER: 172.22.222.5
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-TIME: 3
...

{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "276be6457d8447a4bf1f792501dfba6c"}
```

### Monitor Requests for Malicious Intent

This example shows how to integrate with Chaitin WAF to monitor all routes with `chaitin-waf` without rejection, and to reject potentially malicious requests on a specific route.

Configure the Chaitin WAF connection details using Plugin Metadata (update the address accordingly) and configure the mode:

```shell
curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf" -X PUT \
  -H 'X-API-KEY: ${admin_key}' \
  -d '{
    "nodes": [
      {
        "host": "172.22.222.5",
        "port": 8000
      }
    ],
    "mode": "monitor"
  }'
```

Create a Route and enable `chaitin-waf` without any configuration on the Route:

```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "chaitin-waf-route",
    "uri": "/anything",
    "plugins": {
      "chaitin-waf": {}
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org:80": 1
      }
    }
  }'
```

Send a standard request to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything"
```

You should receive an `HTTP/1.1 200 OK` response.

Send a request with SQL injection to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
```

You should also receive an `HTTP/1.1 200 OK` response as the request is not blocked in the `monitor` mode, but observe the following in the log entry:

```text
2025/09/09 11:44:08 [warn] 115#115: *31683 [lua] chaitin-waf.lua:385: do_access(): chaitin-waf monitor mode: request would have been rejected, event_id: 49bed20603e242f9be5ba6f1744bba4b, client: 172.20.0.1, server: _, request: "POST /anything HTTP/1.1", host: "127.0.0.1:9080"
```

If you explicitly configure the `mode` on a route, it will take precedence over the configuration in the Plugin Metadata. For instance, if you create a Route like this:

```shell
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "chaitin-waf-route",
    "uri": "/anything",
    "plugins": {
      "chaitin-waf": {
        "mode": "block"
      }
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org:80": 1
      }
    }
  }'
```

Send a standard request to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything"
```

You should receive an `HTTP/1.1 200 OK` response.

Send a request with SQL injection to the Route:

```shell
curl -i "http://127.0.0.1:9080/anything" -d 'a=1 and 1=1'
```

You should see an `HTTP/1.1 403 Forbidden` response similar to the following:

```text
...
X-APISIX-CHAITIN-WAF-STATUS: 403
X-APISIX-CHAITIN-WAF-ACTION: reject
X-APISIX-CHAITIN-WAF: yes
X-APISIX-CHAITIN-WAF-TIME: 3
...

{"code": 403, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "c3eb25eaa7ae4c0d82eb8ceebf3600d0"}
```