Published a month ago
Published a month ago
禾
Updated a month ago
1
Why does a visit to the same website sometimes return 403, sometimes 429, and sometimes stop at a challenge page with status code 468? Let’s follow an HTTP/HTTPS request to see exactly what happens as it passes through SafeLine.
This article uses the implementation and interface of SafeLine WAF 9.4.0 as an example. Other versions may differ.
Once traffic enters SafeLine, several services handle it at different stages:
| Service | Role |
|---|---|
| Tengine | The entry and exit point for traffic: receives HTTP/HTTPS requests, matches them to the configured application, connects to the upstream server, and invokes request and response detection. It returns blocking pages, waiting room pages, and maintenance pages. |
| Detector | The detection engine: uses the active detection configuration to decide whether to allow or block a request, or direct it to an anti-bot challenge, authentication, or the Waiting Room. It also generates the anti-bot challenge page and the authentication entry page. |
| MGT | The management service: saves application settings and protection policies, then prepares them as detection configurations for distribution. |
| FVM | The compilation service: compiles the detection configuration prepared by MGT, referred to internally as FSL, into bytecode that Detector can execute directly, then distributes it. |
| TCD | The application configuration service: converts application settings saved by MGT into configuration that Tengine can use, then triggers a reload. |
| Chaos | The service for interactive flows: handles anti-bot challenges, authentication, and the Waiting Room on the request side, and Dynamic Protection on the response side. It has no externally accessible entry point; access to the relevant pages and endpoints must go through Tengine. |
| Luigi | The logging and statistics service: receives detection results asynchronously, stores logs, and tracks request rates. When a rate limit is exceeded, it records a ban that takes effect on subsequent requests. |
| PostgreSQL | Persists configuration, logs, and statistics. |

When a request enters SafeLine, Tengine first matches it to the configured application and passes it to Detector for inspection. Based on the detection result, the request is allowed, blocked, or directed to an anti-bot challenge, authentication, or a queue. Normal requests are forwarded to the upstream application. When the upstream response arrives, Tengine passes it to Detector for response detection. If a blocking rule matches, a blocking page is returned. If Dynamic Protection applies, Chaos rewrites the response before it is returned to the client.
Meanwhile, the results of both inspections are reported asynchronously to Luigi for logging and request-rate statistics. As a result, successive visits from the same source can have very different outcomes:
The first visit goes through normally, and the client receives the upstream response with status code 200.
If frequent visits continue, the source is banned once the count reaches the threshold. A subsequent request is rejected with status code 429. If the rate-limiting policy specifies a challenge instead of a ban, that request stops at an anti-bot challenge page with status code 468.
If a request contains signs of SQL injection, semantic-based detection identifies the attack and blocks the request, returning 403.
How a visit is handled depends on what it matches. First, let’s distinguish two terms that are easy to confuse: “blocking” applies to the current request and returns a blocking page; “banning” records the source in the detection configuration that will take effect later, affecting subsequent requests.
| Scenario | Action | Status Code | Explanation |
|---|---|---|---|
| An attack is identified by semantic-based detection | Block the request and return a blocking page | 403 Forbidden | Identifies common attack techniques such as SQL injection and cross-site scripting (XSS). |
| An enhanced rule matches | Block the request and return a blocking page | 403 Forbidden | Supplementary signatures targeting specific vulnerabilities or attack patterns. |
| A denylist policy matches | Block the request and return a blocking page | 403 Forbidden | Blocks directly based on conditions such as IP address, URL, headers, or parameters, without assessing the content. |
| Response detection triggers a blocking action | Block the request and return a blocking page | 403 Forbidden | Response content is also inspected; blocking is not limited to the request stage. |
| The conditions for a rate-limit ban are met | Reject the request | 429 Too Many Requests | Tracks request rates by source and bans the source when the limit is exceeded. |
| The rate-limiting policy specifies a challenge | Return an anti-bot challenge page | 468 | Uses a challenge instead of a ban when the rate limit is exceeded, reducing the risk of blocking legitimate users. |
| The request triggers an anti-bot challenge policy | Return an anti-bot challenge page | 468 | After completing the challenge, the client sends the request again with a challenge credential. Access continues once the credential is validated. |
| A protected resource is requested before authentication is complete | Return an authentication page | 467 | A valid authenticated session must be established before the target resource can be accessed. |
| A Waiting Room policy matches | Return a waiting room page | 465 | Determines whether to queue the request based on application concurrency and session state. Access resumes once the conditions are met. |
| The application is in maintenance mode | Return a maintenance page | 466 | Reflects the application’s operating state, regardless of request content. The request is not forwarded upstream. |
| The request passes inspection and reaches the upstream server | Continue forwarding | Usually uses the upstream status code | For example, the upstream application may return 200, 404, or an application-defined status code. |
| The response meets the conditions for Dynamic Protection | Modify the response content and return it | Usually preserves the upstream status code | Modifies the response content rather than reclassifying the request as an attack. |
465, 466, 467, and 468 are custom HTTP status codes used by SafeLine. They are not standard status codes, nor are they returned by the upstream application. If a CDN or another proxy sits in front of SafeLine, it may modify the response before it reaches the client. Check the response headers and logs along the request path to determine what happened.
Rate limiting has two possible paths: exceeding the limit can result in a source ban, with subsequent requests returning 429; alternatively, SafeLine can return 468, requiring the client to complete an anti-bot challenge first. In either case, the affected request is generally not the one whose count triggered the limit. There is also another reason for 468: the request itself matches an anti-bot challenge policy, independently of its request rate.
Saving a rule in the console only writes the configuration. Before the new rule can be used to inspect traffic, the configuration must still be generated, compiled, distributed, and loaded:

Application configuration is distributed to Tengine through TCD, while protection policies are compiled by FVM and then loaded by Detector. IP bans generated by rate limiting also depend on this protection-policy distribution process.
Therefore, a “Saved successfully” message in the console only means that the configuration has been written; it does not mean the rule is already in effect. If a rule does not match as expected, check whether compilation, distribution, and loading by Detector have completed, then review the rule match logs to investigate further.
To discuss implementation details or report an issue, join the conversation on our online forum, GitHub Issues, or Discord community.