# How to Implement a Custom Response Filter Using the `-x` Option in Patator

> Learn how to implement a custom response filter in Patator using the -x option. Extend Response_Base, register a condition, and define your filter logic to tailor module responses effectively.

- Repository: [lanjelot/patator](https://github.com/lanjelot/patator)
- Tags: how-to-guide
- Published: 2026-03-05

---

**To implement a custom response filter in Patator, extend the `Response_Base` class to expose your data, register a new condition keyword in `available_conditions`, and implement a `match_<keyword>` method that evaluates the filter logic against module responses.**

Patator's flexible brute-forcing framework allows you to define custom response filters using the `-x` option, which attaches actions like `ignore`, `retry`, or `skip` to conditions evaluated against execution results. This guide walks through the `lanjelot/patator` source code to show you how to extend the built-in filtering system with your own conditions.

## Understanding Patator's Action-Condition Framework

The `-x` option uses a simple syntax: `action:condition=value`. For example, `-x ignore:code=404` tells Patator to ignore responses with HTTP status 404. This framework relies on three core components in [`src/patator/patator.py`](https://github.com/lanjelot/patator/blob/main/src/patator/patator.py):

- **Command-line parsing**: The `Controller.usage_parser()` method (lines 814-822) defines the `-x` option syntax as `actions:conditions`.
- **Action storage**: `Controller.update_actions()` (lines 1011-1030) parses the actions portion and stores conditions in `self.ns.actions`.
- **Condition evaluation**: `Controller.lookup_actions()` (lines 1034-1046) iterates through stored actions and evaluates conditions by calling `resp.match(key, val)` on the `Response` object.

The `Response_Base` class (lines 1530-1563) serves as the foundation for all response filtering. It maintains an `available_conditions` tuple that registers valid filter keywords and implements a generic `match()` dispatcher (around line 1580) that routes condition checks to specific `match_<keyword>` methods.

## Step-by-Step Implementation Guide

### Step 1: Expose Data in the Module Response Class

First, modify the module's `Response` subclass to capture the data you want to filter. Each module (e.g., HTTP, FTP, SSH) defines its own `Response` class inheriting from `Response_Base`.

For example, to filter based on the HTTP `Server` header, add a `server` attribute to the HTTP module's response class:

```python

# Inside the HTTP module (e.g., src/patator/http.py)

class Response(Response_Base):
    def __init__(self, code, mesg, timing=0, trace=None, server=None):
        super().__init__(code, mesg, timing, trace)
        self.server = server  # New attribute for custom filtering

```

Ensure this attribute is populated when the module creates the response object during execution.

### Step 2: Register the New Condition Keyword

Add your condition to `available_conditions` in the `Response_Base` class definition (around line 1556 in [`patator.py`](https://github.com/lanjelot/patator/blob/main/patator.py)):

```python
class Response_Base:
    available_conditions = (
        ('code',  'match status code'),
        ('size',  'match size (N or N-M or N- or -N)'),
        ('time',  'match time (N or N-M or N- or -N)'),
        ('mesg',  'match message'),
        ('fgrep', 'search for string in mesg'),
        ('egrep', 'search for regex in mesg'),
        ('server','match Server header'),   # <-- Your new condition

    )

```

Registration is mandatory—Patator only accepts conditions listed in this tuple when parsing the `-x` argument.

### Step 3: Implement the Matching Logic

Implement a `match_<keyword>` method in `Response_Base` to handle the comparison logic. The method receives the value from the command line and returns a boolean:

```python

# In Response_Base class, following existing match methods (around line 1596)

def match_server(self, val):
    """Match the Server header against a substring pattern."""
    return self.server and val in self.server

```

You can implement complex logic here—regex matching, numeric ranges, or case-insensitive comparisons—depending on your filtering requirements. The `match()` dispatcher automatically calls this method when it encounters the `server` keyword.

### Step 4: Use the Custom Filter

Invoke your custom filter from the command line using the standard `-x` syntax:

```bash
patator http_fuzz url=http://target.com/FUZZ \
         -x ignore:server=nginx \
         0=wordlist.txt

```

This configuration ignores any response where the `Server` header contains "nginx". You can combine multiple conditions using commas: `-x ignore:code=404,server=apache`.

## Code Reference and Architecture

Understanding these specific source locations helps when debugging or extending filters:

- **Option definition**: `Controller.usage_parser()` at line 814 adds the `-x` flag and builds help text.
- **Action parsing**: `Controller.update_actions()` at line 1011 separates actions from conditions.
- **Condition lookup**: `Controller.lookup_actions()` at line 1034 triggers `resp.match()`.
- **Built-in conditions**: Defined in `Response_Base.available_conditions` at line 1556.
- **Dispatch mechanism**: `Response_Base.match()` at line 1580 routes to `match_<keyword>` methods.

Module-specific response classes inherit from `Response_Base` and can override `available_conditions` or add module-specific match methods, though registering conditions in the base class makes them available globally.

## Summary

- **Extend `Response_Base`**: Add your data attribute to the module's `Response` class constructor.
- **Register the keyword**: Append a tuple to `available_conditions` in `Response_Base` to enable parsing.
- **Implement `match_<keyword>`**: Create the evaluation method that returns `True` when the condition matches.
- **Execute with `-x`**: Use the syntax `action:keyword=value` (e.g., `-x ignore:server=nginx`) to activate your filter.

This architecture allows you to filter on any response attribute—from HTTP headers and LDAP error codes to custom protocol fields—without modifying Patator's core execution logic.

## Frequently Asked Questions

### What is the syntax for the `-x` option in Patator?

The `-x` option accepts a string in the format `actions:conditions`, where actions are comma-separated keywords like `ignore`, `retry`, or `stop`, and conditions use the syntax `keyword=value`. Multiple condition pairs can be chained with commas: `-x ignore:code=200,size=0`. The `Controller.update_actions()` method at line 1011 parses this string into actionable tuples.

### Where are the built-in conditions defined in Patator?

Built-in conditions are defined in the `available_conditions` class attribute of `Response_Base` at line 1556 in [`src/patator/patator.py`](https://github.com/lanjelot/patator/blob/main/src/patator/patator.py). The default conditions include `code` (status code), `size` (response size), `time` (execution time), `mesg` (message text), `fgrep` (substring search), and `egrep` (regex search). Each condition has a corresponding `match_<keyword>` method that implements the comparison logic.

### Can I use regex patterns in custom response filters?

Yes. While the example above uses simple substring matching, you can implement regex matching by importing the `re` module and using `re.search()` inside your `match_<keyword>` method. The built-in `egrep` condition demonstrates this pattern in the source code. Ensure your method handles cases where the attribute might be `None` to avoid attribute errors during execution.

### How do I debug a custom filter that isn't matching?

First, verify that your condition keyword appears in `Response_Base.available_conditions` and that your module's `Response` class actually populates the attribute you're filtering on. You can temporarily add debug prints to your `match_<keyword>` method to inspect the `self` object's attributes. Also confirm that the `-x` syntax uses the exact keyword you registered—Patator's `lookup_actions()` method silently skips unrecognized conditions rather than throwing errors.