Security Rules

Overview

Security Rules are ordered, first-match-wins rules that evaluate the coreX expression language against request properties and execute an action. They are the primary access control and traffic shaping mechanism in coreX Manager, sitting between WAF evaluation and backend routing.

Each rule has:

  • A name for identification
  • An expression in the coreX expression language
  • An action to execute when the expression matches
  • A priority (drag-and-drop ordering)
  • Listener scoping (which listeners the rule applies to)

The coreX Expression Language

The expression language is coreX Manager’s own DSL for matching request properties. It supports field access, comparison operators, logical operators, and list membership.

Fields

FieldDescription
http.request.methodHTTP method (GET, POST, etc.)
http.request.uriFull request URI (path + query)
http.request.uri.pathRequest path only
http.request.uri.queryQuery string
http.request.headers["name"]Request header value
http.request.hostHost header
http.request.user_agentUser-Agent header
http.request.content_typeContent-Type header
http.request.bodyRequest body (when buffered)
http.request.cookies["name"]Cookie value
ip.srcClient IP address
ip.geoip.countryClient GeoIP country code
ip.geoip.cityClient GeoIP city
ip.geoip.asnClient ASN
tls.ja4JA4 TLS fingerprint
tls.versionTLS version
tls.cipherNegotiated cipher
auth.validWhether auth validation passed
auth.typeDetected auth type (jwt, api_key, bearer)
risk.scoreRisk score (0-99) from Risk Scoring
risk.rules_hitNames of matched risk rules
risk.rules_hit_countCount of matched risk rules
risk.hit_densityRisk hit density percentage
risk.<slug>.scorePer-ruleset risk score
waf.anomaly_scoreWAF anomaly score
waf.actionWAF action taken
rate_limit.exceededWhether rate limit was exceeded

Operators

OperatorDescription
==Equal
!=Not equal
> / >=Greater than / greater or equal
< / <=Less than / less or equal
inMembership in a Security List
not inNot in a Security List
containsString contains substring
matchesRegex match
andLogical AND
orLogical OR
notLogical NOT

Examples

ip.geoip.country in $geo:high_risk_countries
http.request.uri.path matches "^/admin"
http.request.method == "POST" and http.request.content_type contains "json"
ip.src in $network:blocked_networks
risk.score > 50 and not auth.valid
tls.ja4 in $ja4:bad_fingerprints
http.request.headers["x-api-key"] == ""
Security List references

Security Lists are referenced with the $type:name syntax (e.g. $geo:high_risk_countries, $network:blocked_networks). The list must exist before the rule can be applied.

Actions

ActionDescription
allowPermit the request through
denyBlock with 403
challengePresent a CAPTCHA challenge
logLog the request but allow it through
tarpitBlock and hold the connection (block duration)
skip_rulesSkip subsequent security rules
skip_ratelimitSkip rate limiting for this request
skip_wafSkip WAF evaluation for this request

Rule Ordering

Rules are evaluated in priority order (drag-and-drop). The first rule whose expression matches determines the action. If no rules match, the request is allowed through to backend routing.

First-match-wins

Only the first matching rule’s action is executed. Place more specific rules above more general ones. For example, a rule that allows a specific IP should come before a rule that blocks a broader range containing that IP.

Listener Scoping

Each rule can be scoped to specific listeners:

ScopeDescription
All listenersRule applies to every listener (default)
Specific listenersRule applies only to selected listener IDs
Frontend matchRule applies to listeners matching a frontend name pattern

Step-by-Step: Block a Country

  1. Create a GeoIP Security List:

    • Navigate to Security > Security Lists > GeoIP tab
    • Add a list named blocked-countries
    • Add country codes (e.g. XX, YY)
    • Save
  2. Create the Security Rule:

    • Navigate to Security > Security Rules
    • Click Add Rule
    • Name: block-high-risk-countries
    • Expression: ip.geoip.country in $geo:blocked_countries
    • Action: deny
    • Scope: All listeners (or specific)
    • Save
  3. Apply:

    • Click Apply Changes

Step-by-Step: Challenge High-Risk Requests

  1. Ensure Risk Scoring is configured (see Risk Scoring)

  2. Navigate to Security > Security Rules

  3. Click Add Rule

  4. Name: challenge-high-risk

  5. Expression: risk.score > 50

  6. Action: challenge

  7. Save and Apply

Combine with auth

Use and not auth.valid to only challenge unauthenticated requests: risk.score > 50 and not auth.valid. This avoids challenging known-good API clients.

Step-by-Step: Skip WAF for a Trusted Path

  1. Navigate to Security > Security Rules
  2. Click Add Rule
  3. Name: skip-waf-webhooks
  4. Expression: http.request.uri.path matches "^/webhooks/" and http.request.headers["x-webhook-secret"] == "my-secret"
  5. Action: skip_waf
  6. Save and Apply

Verification

  1. Preview the config — on the Dashboard, click Preview and search for your rule name in the generated HAProxy config
  2. Test with a matching request:
    curl -k https://localhost/ -H "X-Test: match"
  3. Test with a non-matching request:
    curl -k https://localhost/
  4. Check access logs — navigate to Observability > Access Logs and verify the security rule action is logged

Next Steps

  • Security Lists — Create reusable IP, ASN, GeoIP, and JA4 lists
  • Risk Scoring — Score requests and reference scores in rules
  • WAF — Layer Coraza WAF rules
  • CAPTCHA — Configure challenge providers