Rules & Rulesets
The managed rule sets: OWASP CRS and the EdgeGuard sets, paranoia levels, anomaly scoring, and what a category switch really turns off.
Rules & Rulesets is the detection itself: the OWASP Core Rule Set, EdgeGuard's own rules, and any you write. Unlike a firewall rule, these do not decide alone — each match adds a score, and the request is refused when the total crosses the site's threshold.
How detection decides
A request that survives the earlier steps — path rules, IP lists, threat intelligence, geo, firewall rules, bots, rate limits — reaches the rulesets. Then:
- Every enabled rule whose category is enabled, and whose paranoia level is within the site's, is evaluated against the parts of the request it targets.
- Each rule that matches contributes its score. One hit per category: five SQLi patterns matching is still one SQLi hit.
- The scores accumulate into an anomaly total.
- The total is compared with the site's Inbound Anomaly Threshold (Global Settings → General; default 5). At or above it, the request is refused.
So a rule scoring 5 blocks on its own at the default threshold, and two rules scoring 3 block together. This is why raising the threshold is a blunt instrument: it does not make one noisy rule quieter, it makes every combination harder to reach.
Static assets skip this step. A plain file fetch has no injection surface, and the regex work is the most expensive thing the engine does, so the fast path leaves it out.
Paranoia levels. Every rule carries one. PL1 rules always run; a rule at PL2 or above runs only if the site's CRS Paranoia Level is at least as high. PL1 is the default and is what you should stay on until you have time to tune: PL2 and above trade false positives for coverage, deliberately.
Category switches win. Turning a category off in Global Settings → Attack Detection silences both EdgeGuard's own matchers and the CRS rules of that category — including when a path rule turns it off for one path. Without that, disabling "RCE detection" would silence the built-in detector while CRS 932xxx kept scoring, and the request would stay blocked for a reason the setting appeared to cover. Categories with no switch — protocol, Log4Shell, custom — always evaluate.
There is a time budget. A crafted input can make many rules backtrack; the engine stops evaluating early, keeps what it found, and records that it did, rather than spending a core on one request.
Managed Rulesets

One card per ruleset. Each shows the source (owasp-crs), its category tag (sqli, rce, lfi, protocol, data_leakage…), the CRS version it came from, how many rules it holds, how many times it has matched, and whether it is enabled.
The filter buttons above narrow the list by category: All, SQLi, XSS, CMDi, RCE, LFI, SSRF, XXE, SSTI, NoSQLi, Open Redirect, Header Inj., Deserialization, Log4Shell, Protocol, Custom.
The hits figure is the one worth reading. Twenty-nine rulesets are loaded and they overlap heavily; the count is what tells you which earn their place and which have never matched anything on your traffic.
Inside a ruleset
Expand a card to see its rules:

| Column | Meaning |
|---|---|
| ID | the CRS rule number — 942100, 942140… This is the number that appears in an event and in an exclusion |
| NAME | what it detects, e.g. SQL Injection Attack Detected via libinjection |
| PATTERN | the regular expression, or @detectSQLi for the libinjection detector |
| TARGETS | which part of the request it reads: uri, query, args, body, or all |
| ACTION | what it contributes — most are block, meaning "add score toward a block" |
| SEVERITY | critical, error, warning, notice — which is what the score derives from |
| ENABLED | a single rule can be switched off without touching the rest of its ruleset |
Switching off one rule is almost always better than switching off its category, and writing an exclusion for it is better still — see False Positives.
CVE channel

The third tab lists what the channel publishes. Per rule: what it does in one sentence, whether any of your own sites runs the affected software, the identifiers it patches linked to their NVD entries, which part of a request it reads, and its severity.
The pattern sits behind what it matches rather than in a column of its own. A regular expression is information for whoever wrote it: nobody evaluates one from a table to decide whether they are covered, and a column of them makes a page look technical without making it clearer. It is one click away for when you do want it.
Each rule says one of three things, and the difference matters:
| It says | It means |
|---|---|
| Blocks the attack on its own | A matching request is refused. Severity critical reaches the default threshold alone |
| Contributes to a block rather than causing one | A request is refused when this rule and another match. On its own the request is recorded and allowed |
| Watching, not blocking | A match is recorded so you can see what the rule would catch. Nothing is refused |
The third is action: "log", and it is how a rule is published to be watched before it is allowed to act.
It exists because a rule for a newly published vulnerability should not have to wait for an engine release. Each edge node fetches the same document hourly and enforces it locally, so a publish reaches the fleet within the hour — or immediately, with Update rulesets on an agent.
The tab is read from that same document rather than from the rulesets table, and deliberately: the rules the channel ships are owned by the channel, and central does not own them. A node's configuration pull leaves them alone, so a patch that arrived from the channel survives a config change that would otherwise delete anything central does not know about.
Nothing published is the resting state, not a fault. A rule is added when an advisory calls for one and withdrawn when it no longer does; most of the time there is nothing to carry. The panel states this rather than showing an empty table and leaving the reader to guess.
When one of these rules refuses a request, the event names it by id, with its identifiers linked — see PHP2Shell for one read end to end.
Who writes these, and how one blocks
Artica writes them, by hand. This is the one source of rules on this page that is neither upstream nor automatic, and the distinction is worth having clearly:
| Source | Rules | Written by | Updated |
|---|---|---|---|
| The engine's own detection | 621 patterns | Artica, in code | with an engine release |
| The engine's built-in rulesets | 61 | Artica, in code | with an engine release |
| Managed Rulesets (OWASP CRS) | ~240 | the OWASP project | automatically, from upstream |
| CVE channel | a handful | Artica, by hand | published as data, no release |
| Learned Rules | varies | your own traffic | proposed for your decision |
The channel cannot be automated from a vulnerability database, and that is not a gap waiting to be filled. A CVE record describes the vulnerability, not the request: "CrushFTP 11.x before 11.3.1 allows unauthenticated access" contains nothing a WAF can match against. Somebody has to know what the attack looks like. Generated from the text alone, a rule either matches nothing or matches everything — and on a WAF the second takes a site down.
How a rule decides. The pattern is matched against the part of the request its target names. The console says which in words — the address requested, the names of the parameters sent, the name of an uploaded file — and the underlying targets are uri, query, args, param_names, body, headers, cookies, user_agent, filename and all.
A match does not refuse the request on its own: the severity becomes an anomaly score and the site's threshold decides.
| Severity | Score | On its own, against the default threshold of 5 |
|---|---|---|
critical |
5 | refuses |
high |
4 | does not reach it — another rule has to fire too |
medium |
3 | needs others |
low |
2 | almost no effect alone |
This is OWASP anomaly scoring: several suspicions add up to a threshold, rather than one isolated suspicion ending a request. A rule published with "action": "log" is the exception — it records the match as an event and scores nothing, so it can neither refuse a request nor push another rule over the line. That is how a patch is published to watch before it is allowed to act.
For your own CVE rules, use a custom ruleset
The channel is for what Artica pushes to every installation at once, which is rare: an actively exploited, remotely recognisable vulnerability in the days before a real fix exists. Anything that stays dangerous belongs in the engine, where it works with no network and cannot be withdrawn by accident — which is where Log4Shell, Spring4Shell and PHP2Shell live.
Your own rules do not go through us at all. Use Create Custom Ruleset on the first tab: it takes the same fields a channel rule has — pattern, targets, action, score, severity, category and the CVE identifier — and it reaches your agents through the ordinary configuration pull, scoped to the sites or groups you choose. Nobody else sees it and no publication by Artica can clear it: a node's configuration pull is forbidden from touching the sources the feed owns, and the feed is forbidden from touching yours.
Pointing the channel at your own document
From engine 3.2.7, an installation can read its own channel instead of the published one:
{ "ruleset_feeds": { "enabled": true, "cve_url": "https://your.host/cve.json" } }
It replaces the published channel rather than adding to it. The channel owns its ruleset source — a fetch clears that source before rebuilding it, which is what lets a rule be withdrawn — so two documents claiming it would delete each other's rules on alternating ticks. rulesets_url does the same for the CRS mirror, and leaving both unset is the right default: you get the patches Artica publishes.
This is for rehearsing a rule against your own traffic before anyone else sees it, or for an estate that would rather not read a document it does not control.
So the short version: the channel is Artica's emergency lane, a custom ruleset is yours, and now the channel itself can be yours too.
OWASP Top 10

The same protection read the other way round: A01 through A10, and what covers each. This is the view to bring to an auditor, and the quickest way to notice that a category you switched off has left a gap in the Top 10.
Rule Feed Auto-Update

The engine fetches updated rule definitions on a schedule; the Artica EdgeGuard feed is always included.
- Auto-update enabled — whether to fetch at all.
- Check interval (hours) — how often.
- Additional feed URLs — one per line, for your own or a third party's rules.
- Refresh Now — fetch immediately, which is what you use after publishing a rule of your own.
- Save Feed Config — applies the settings.
The current feed version is shown on each ruleset card, so you can tell at a glance whether an agent is running rules from last month.
Writing your own ruleset

Click Create Ruleset.
- Name, Version and Description — what it detects and why it exists.
- Category — SQLi, XSS, CMDi, RCE, LFI, SSRF, XXE, SSTI, NoSQLi, Open Redirect, Header Injection, Deserialization, Log4Shell or Protocol. The category decides which switch turns it off later, so pick the one an operator would think of.
- Source — Custom, OWASP or CVE. Use CVE when the ruleset exists because of a specific vulnerability; the number belongs in the description.
- Add Rule for each pattern, then for each rule: the regular expression, what it targets, its score and severity.
- Test — paste a sample input and see whether the pattern matches it. Use it on both a payload that should match and one that should not.
- Create Ruleset.
Test every pattern against something that should not match. A regular expression that matches everything looks identical to protection until the first complaint. The Test box exists for exactly this, and it costs ten seconds.
Cost. Your pattern runs on every request that is not a static asset. Avoid nested quantifiers ((a+)+), prefer anchored and specific expressions, and keep the target as narrow as the attack allows — a rule that only makes sense in a body should not read the URI.
Verifying
1. Does the rule match what you meant? Use Test in the builder before saving.
2. Does it fire on real traffic?
curl -o /dev/null -w '%{http_code}\n' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/140.0.0.0' \
"https://site.example.com/?id=1%20UNION%20SELECT%20password%20FROM%20users"
3. What did EdgeGuard think? Open the newest row in Security Events. The detail panel names every rule that matched, what it matched on, the accumulated score and the threshold it was compared against. If the request was allowed, the score will tell you how close it came.
4. Is the ruleset doing work over time? The hits figure on its card, and the Rule Coverage table on Analytics, which lists rules that are firing and rules that are silent in this window.
Tuning, in order of preference
- An exclusion for the one rule on the one path or field that is wrong — narrowest, and it keeps everything else inspecting. See False Positives.
- Disable the single rule inside its ruleset, when it is wrong everywhere rather than in one place.
- A path rule that turns a category off for one endpoint.
- Lower the paranoia level, if you raised it and the noise came with it.
- Raise the anomaly threshold — last, and reluctantly. It weakens every combination of rules, not the one that annoyed you.
The False Positive Rate Estimate table on Analytics is the evidence for which of these you need: it shows, per rule, how many events it produced and how many a person marked as false positives.
Learning mode (Global Settings → General → WAF Operating Mode) is the safe way to introduce a stricter setting: everything is detected and logged, nothing is refused, and the Analytics tables then tell you what would have happened.