Skip to content
This page was generated and translated with the assistance of AI. If you spot any inaccuracies, feel free to help improve it. Edit on GitHub

Custom Rules

PRX-WAF makes it straightforward to write custom detection rules tailored to your specific application. Custom rules are written in YAML and placed in the rules/custom/ directory.

Getting Started

  1. Create a new YAML file in rules/custom/:
bash
cp rules/custom/example.yaml rules/custom/myapp.yaml
  1. Edit the file following the YAML rule schema.

  2. Validate before deploying:

bash
python rules/tools/validate.py rules/custom/myapp.yaml
  1. Rules are hot-reloaded automatically, or trigger a manual reload:
bash
prx-waf rules reload

Example: Block Access to Internal Paths

Prevent external access to internal API endpoints:

yaml
version: "1.0"
description: "Block access to internal paths"

rules:
  - id: "CUSTOM-ACCESS-001"
    name: "Block internal API endpoints"
    category: "access-control"
    severity: "high"
    paranoia: 1
    field: "path"
    operator: "regex"
    value: "(?i)^/(internal|_debug|_profiler|actuator)/"
    action: "block"
    tags: ["custom", "access-control"]

Example: Detect Suspicious User-Agents

Log requests from automated tools for monitoring:

yaml
  - id: "CUSTOM-BOT-001"
    name: "Log suspicious automated tool user-agents"
    category: "scanner"
    severity: "medium"
    paranoia: 2
    field: "user_agent"
    operator: "regex"
    value: "(?i)(masscan|zgrab|python-requests/|go-http-client|curl/)"
    action: "log"
    tags: ["custom", "bot", "scanner"]

Example: Rate Limit by Query Parameters

Block requests with an excessive number of query parameters (common in DoS attacks):

yaml
  - id: "CUSTOM-DOS-001"
    name: "Block excessive query parameters"
    category: "dos"
    severity: "medium"
    paranoia: 1
    field: "query_arg_count"
    operator: "gt"
    value: "50"
    action: "block"
    tags: ["custom", "dos"]

Example: Block Specific File Extensions

Prevent access to backup or configuration files:

yaml
  - id: "CUSTOM-FILE-001"
    name: "Block access to backup and config files"
    category: "access-control"
    severity: "high"
    paranoia: 1
    field: "path"
    operator: "regex"
    value: "(?i)\\.(bak|backup|old|orig|sql|tar|gz|zip|7z|rar|conf|env|ini|log)$"
    action: "block"
    tags: ["custom", "access-control", "file-extension"]

Example: Detect Credential Stuffing

Detect rapid-fire login attempts (useful alongside the built-in rate limiter):

yaml
  - id: "CUSTOM-AUTH-001"
    name: "Log login endpoint access for monitoring"
    category: "access-control"
    severity: "low"
    paranoia: 1
    field: "path"
    operator: "regex"
    value: "(?i)^/(api/)?(login|signin|authenticate|auth/token)"
    action: "log"
    tags: ["custom", "authentication", "monitoring"]

Example: CVE Virtual Patch

Create a quick virtual patch for a specific vulnerability:

yaml
  - id: "CUSTOM-CVE-001"
    name: "Virtual patch for MyApp RCE (CVE-2026-XXXXX)"
    category: "rce"
    severity: "critical"
    paranoia: 1
    field: "body"
    operator: "regex"
    value: "(?i)\\$\\{jndi:(ldap|rmi|dns)://[^}]+\\}"
    action: "block"
    tags: ["custom", "cve", "rce"]
    reference: "https://nvd.nist.gov/vuln/detail/CVE-2026-XXXXX"

Using Rhai Scripts for Complex Logic

For rules that require more than pattern matching, PRX-WAF supports Rhai scripting in Phase 12:

rhai
// rules/custom/scripts/geo-block.rhai
// Block requests from specific countries during maintenance
fn check(ctx) {
    let path = ctx.path;
    let country = ctx.geo_country;

    if path.starts_with("/maintenance") && country != "US" {
        return block("Maintenance mode: US-only access");
    }

    allow()
}

INFO

Rhai scripts run in a sandboxed environment. They cannot access the filesystem, network, or any system resources outside the request context.

Best Practices

  1. Start with action: log -- Monitor before blocking to catch false positives early.

  2. Use specific regex anchors -- Use ^ and $ to prevent partial matches that cause false positives.

  3. Set appropriate paranoia levels -- If a rule might match legitimate traffic, set paranoia to 2 or 3 instead of blocking at level 1.

  4. Use non-capturing groups -- Use (?:...) instead of (...) for clarity and performance.

  5. Add descriptive tags -- Tags appear in the admin UI and help with filtering security events.

  6. Include references -- Add a reference URL linking to the relevant CVE, OWASP article, or internal documentation.

  7. Test your regex -- Validate regex patterns before deploying:

bash
python3 -c "import re; re.compile('your_pattern')"
  1. Validate before deploying -- Always run the validator:
bash
python rules/tools/validate.py rules/custom/

Importing via CLI

You can also import rules from files or URLs using the CLI:

bash
# Import from a local file
prx-waf rules import /path/to/rules.yaml

# Import from a URL
prx-waf rules import https://example.com/rules/custom.yaml

# Validate a rule file
prx-waf rules validate /path/to/rules.yaml

Importing ModSecurity Rules

Convert existing ModSecurity .conf rules to PRX-WAF YAML format:

bash
python rules/tools/modsec2yaml.py input.conf output.yaml

WARNING

The ModSecurity converter supports a basic subset of SecRule directives (ARGS, REQUEST_HEADERS, REQUEST_URI, REQUEST_BODY). Complex ModSecurity rules with chaining or Lua scripts are not supported and need to be rewritten manually.

Next Steps

Released under the Apache-2.0 License.