This is the multi-page printable view of this section. .

Return to the regular view of this page.

Protection

Semantic engine, custom rules, IP and geo, bot challenges, rate limits, ACL, and block pages.

Global defaults live under protection and protection.policy. A site can overlay sites[].waf.protection_policy.

Console pages: Protection, Rules, IP, Bot challenge, Block pages.

Method, path, and header denies.

1 - Semantic engine

Multi-stage decoding and AST checks. Toggle engines per site.

The semantic engine does not ship a huge regex corpus as the primary detector. It decodes the parameter, then walks an abstract syntax tree for the enabled families.

Enable engines

Under sites[].waf.semantic_engines:

KeyLooks for
sqlSQL injection
xssCross-site scripting
rceCommand / RCE
lfiLocal file include
xxeXML external entity
ssrfServer-side request forgery
nosqlNoSQL injection
sstiServer-side template injection

Turn an engine off when that family cannot appear on the site. Do not turn them all off and expect CheeseWAF to still catch web attacks.

Budget and allow lists

sites[].waf.semantic_policy:

  • budget_exhausted_policy: auto follows the web_attack policy when the analysis budget is spent
  • path_allowlist: skip semantic analysis on these paths
  • param_allowlist: skip these parameter names

sites[].waf.performance caps max_body_bytes, max_header_bytes, and proxy_timeout.

Response inspection

sites[].waf.response can scan the origin body for leaked secrets (AWS key pattern, password assignments, and similar). Keep max_body_bytes modest.

How isolated vs embedded hits are treated: Isolated vs embedded.

2 - Custom rules

Regular-expression rules on URI and other locations, with priority and severity.

Custom rules sit next to the semantic engine. They are useful for admin probes, scanner paths, and one-off business denials.

Console: Rules. REST: /api/rules and sites[].waf.custom_rules.

The sample ships this rule:

YAML
custom_rules:
  - id: "block-admin-probe"
    name: "Admin path probe"
    pattern: "(?i)/(wp-admin|phpmyadmin|\\.git)"
    location: "uri"
    action: "block"
    severity: "medium"
    enabled: true
    priority: 180
FieldMeaning
idStable id
patternRegular expression
locationWhere to match. Sample uses uri
actionUsually block
severityShown in logs and review
priorityLower number runs earlier when the engine sorts that way — keep ids unique

Do not try to rebuild a full ModSecurity ruleset here. Use custom rules for short, reviewable patterns.

3 - IP, geo, and fingerprint

Allow lists, deny lists, GeoIP, reputation overrides, and threat-intel feeds.

Console: IP. Config: protection.ip. REST: /api/ip, /api/protection/ip, /api/ip/threat-intel/*.

Static lists

YAML
protection:
  ip:
    whitelist: ["127.0.0.1", "::1"]
    blacklist: []
    access_rules: []
    reputation_overrides: {}
    tags: {}
    threat_intel: []
    geoip:
      enabled: false
      database: "./data/GeoLite2-Country.mmdb"
      blocked_countries: []

Allow-listed addresses skip later IP denies. Deny-listed addresses never reach the semantic engine.

GeoIP

Set geoip.enabled: true and point database at a MaxMind-style Country MMDB. blocked_countries uses ISO country codes. CheeseWAF does not download GeoLite2 for you.

Threat intel

Operators can import, export, sync, and test providers from the console. Lookups are available at POST /api/ip/threat-intel/lookup.

Fingerprints

The data plane records a soft client fingerprint (not a hardware TPM identity). After a high-confidence review, ALAP can save a fingerprint deny rule. Treat fingerprint hits as supporting evidence, not as the only control.

When CheeseWAF sits behind another proxy, fill sites[].waf.access_control.trusted_cidrs or trusted_proxy_providers so the client IP is not the proxy’s address.

4 - Bot challenge and CAPTCHA

JS clearance, PoW, slider, image CAPTCHA, login CAPTCHA, and the waiting room.

Console: Bot challenge, plus CAPTCHA lab for operators who design challenges. Config: protection.bot and console.login.captcha.

The sample starts with protection.bot.enabled: false. Turn it on only after you have a site that can complete a browser challenge.

Traffic challenge

KeyRole
js_challengeIssue a JS clearance cookie
captchaExtra CAPTCHA after JS
captcha_typepow, image, or slider
cookie_nameDefault cheesewaf_js_clearance
path_prefixesWhere the challenge applies
exempt_path_prefixesSkip, sample includes /health
suspicious_user_agentsExtra scrutiny for curl, sqlmap, nuclei, and similar

Keep secret out of git. Let the process generate it into the data directory.

Challenge kinds

  • PoW / Altcha. Header X-CheeseWAF-Altcha by default.
  • Slider. Geometry and min-drag live under slider_captcha_*.
  • Image. Length, size, and audio-limit knobs.
  • Behavior pack. Curve draw, scratch, icon click, and related lab types. Use the lab before you enable them on production traffic.

Upload custom assets under /api/captcha/assets. Quota and remote source tests are on the same console page.

Login CAPTCHA

console.login.captcha protects the management login, not the data plane. The sample uses a slider with an optional PoW.

console.login.security_entry can hide the login behind a secret path and cookie.

Waiting room

waiting_room plus waiting_room_max_active queues excess clients instead of dropping them immediately. See also Rate limit.

5 - Rate limit

Token-bucket limits on the data plane. API-specific limits live under apisec.

Config: protection.ratelimit. REST: PUT /api/protection/ratelimit.

YAML
protection:
  ratelimit:
    enabled: true
    default:
      requests: 100
      window: 60s
      burst: 20

This is a token bucket on the data plane. It is not the same as apisec.rate_limits, which match one method + path on discovered APIs.

When the bucket is empty, CheeseWAF can:

  • return a 429-style block page
  • or send the client to the waiting room when that is enabled

Start with the sample numbers. Lower requests only after you have a week of logs.

6 - ACL

Deny or allow by HTTP method, path prefix, and header.

Config: protection.acl. REST: PUT /api/protection/acl.

The sample denies /debug:

YAML
protection:
  acl:
    enabled: true
    rules:
      - id: "deny-debug"
        name: "Deny debug endpoints"
        method: ""
        path_prefix: "/debug"
        header: ""
        header_value: ""
        action: "block"
        severity: "high"
        enabled: true

Empty method means any method. Set header + header_value to require or reject a header.

ACL runs early. Use it for operator-known junk paths. Use custom rules when you need a regex, not a prefix.

7 - Block pages

Built-in templates, custom HTML, and a preview window.

Config: block_page. Console: Block pages. REST: /api/block-pages/*.

YAML
block_page:
  template_id: "minimal"
  custom_enabled: false
  custom_html: ""

GET /api/block-pages/templates lists built-in templates. POST /api/block-pages/preview and the /block-pages/preview window show the rendered page without publishing it.

Upload custom HTML with POST /api/block-pages/upload. Delete it with DELETE /api/block-pages/custom.

A block page can include a trace id. Give that id to the operator when you open a log detail. Do not put origin hostnames or internal IPs in custom HTML.