Detection rules
Overview
Section titled “Overview”A match rule answers “does this one request match?”. A detection rule answers a question over time, about one of the signals Shield360 collects: “has anyone had more than 20 sensitive-data blocks in the last hour?”, “is this person spending three times their norm?”, “did an agent read a secrets file and then call out to the network?”.
Both kinds live under Govern → Policies & rules → Detection rules (/rule-engine). The Rules tab shows every rule with its kind (Match, Threshold, Baseline, Sequence, First seen or Absence), whether it is on, when it last ran and matched, and the error from its last run, if there was one. Match rules keep working exactly as before.
Kinds of detection
Section titled “Kinds of detection”| Kind | Fires when | Example |
|---|---|---|
| Threshold | A count, sum, distinct count or rate per minute of a signal over a window, per group, is above or below a value | More than 20 blocked sensitive-data decisions for one person in an hour |
| Baseline | The same aggregate is far above the group’s own history: a multiple of its mean, or a number of standard deviations above it (z-score) | A person’s estimated spend in a day at three times their norm over two weeks |
| Sequence | One event and then another by the same person, machine, agent or session within a time | An agent reads a .env file, then runs curl within 10 minutes |
| First seen | A value appears that was not seen in the lookback, for everyone or per group | A coding agent calls an MCP tool not seen in 30 days |
| Absence | Something that reported in the expected period has reported nothing for a time | A machine whose guard reported yesterday has been silent for a day |
Every kind can filter a signal’s events first, with the same operators as match rules: equals, contains, starts with, regex, in, greater than, between and the rest.
How a baseline decides
Section titled “How a baseline decides”The window that has just ended is compared with the same group’s earlier windows over the history you choose, up to 30 days. A window with nothing in it counts as zero. With Same time in earlier weeks, only the same window in earlier weeks is used, so Monday morning is compared with Monday mornings.
A baseline fires only when:
- the current value is at least the minimum value you set,
- it is above the group’s mean,
- the group has a norm to compare with: at least three earlier windows with something in them (or all of them, when there are fewer),
- and its score reaches the threshold. For multiple of the mean the score is the value divided by the mean; for z-score it is how many standard deviations above the mean it is. A history that never varies is given a small spread (a tenth of the mean) so that any rise does not score as infinite.
Signals
Section titled “Signals”| Signal | What it holds | Grouped by |
|---|---|---|
| Guard decisions | Each time a guard blocked, masked, warned about or allowed sensitive data, an AI tool or a model, with its outcome (including sent anyway) | Person, machine, agent, model, tool, session |
| Prompt-injection detections | Prompt injection found in what coding agents and gateway agents read or sent | Person, machine, agent, tool, session |
| Sequence policy violations | Sequence policies that held | Person, machine, agent, tool, session |
| AI usage | Tokens and estimated list-price cost reported by the collector | Person, machine, tool, model, project |
| AI site activity, app activity | Time spent on AI websites and in desktop apps | Person, machine, vendor or app |
| Network observations | Processes seen talking to AI providers, and the keys they used, as fingerprints | Person, machine, vendor, process, vendor key |
| Browsing visits | Pages visited, by domain, where browsing collection is on | Person, machine, domain |
| Collector check-ins | Each collector’s regular heartbeat | Person, machine |
| Coding-agent tool calls | Tool calls from coding agents’ traces, with permission mode and MCP server | Person, machine, agent, tool, session, repeated call |
| OpenShell sandbox decisions | What OpenShell sandbox policies allowed and denied: connections, HTTP requests, process launches and policy loads | Person, machine, agent, tool (binary), destination domain, sandbox |
| Agent actions (activity provenance) | Every action an AI agent took: its type, target, privilege, result, policy decision and cost. The action text can be filtered on and is never shown | Person, machine, agent, model, tool, session, target host |
| Alerts | Alerts raised in the environment, other than detection alerts | Person, machine, agent, tool, model, where the alert carries them |
| Audit events | Changes, reads and sign-ins in the audit log | Person |
| AI inventory assets | Tools, models, vendors, keys, agents and MCP servers, by when each was first seen | Asset, vendor, model, tool |
A rule can only be saved or previewed by someone allowed to read every signal it reads: guard decisions need View data protection events, audit events need Read the audit log, AI usage needs View costs, and so on. Tool-call arguments can be filtered on (to find a read of a secrets file) but are never shown, returned or sent anywhere.
Build a rule
Section titled “Build a rule”You need Configure the rule engine, and the permission of every signal the rule reads. Without it the page says “Your role can read detection rules but not change them.”
Open Govern → Policies & rules → Detection rules, choose New detection, then the kind: Threshold, Baseline, Sequence, First seen or Absence. The New detection rule page opens with that kind’s defaults.
Under Rule, give it a Name (up to 120 characters), a Severity (Info, Warning or Critical; the default is Warning) and, optionally, a Description.
Under What to detect, pick the Signal. A signal your role cannot read is marked “(your role cannot read this)”. To count only some of its events, choose Add filter under Only events where, then a Field, an Operator and a Value. A list (in, not in) is written a,b,c; between is written low,high. With no filters, every event of the signal counts.
The fields depend on the kind:
- Threshold: the Measure (Count of events, Sum of a measure, Distinct count of a grouping, or Events per minute), Per (a grouping, or Everything together), Fires when it is above, at or above, below, or at or below a Value, and the Window (minutes) each run looks back over.
- Baseline: the same measure, grouping and window, then History (days), Compare with (Every earlier window or Same time in earlier weeks), the Method (Multiple of the mean or Standard deviations above the mean (z-score)), the multiple or z-score at which it fires, and a Minimum value below which it never fires.
- Sequence: a First and a Then step, each with its own signal and filters, Done by the same person, machine, agent or session (only groupings both signals have are offered), Within (minutes) of each other, and the window.
- First seen: the value that must be New (a model, tool, domain, key…), New for everyone or per group, Not seen in (days), and the window.
- Absence: Per what, Silent for (minutes), and Having reported in (days): only what reported in that many days before going silent counts.
Under Schedule, set Run every (minutes) (default 15) and Cooldown (minutes) (default 60): once a group has matched, it is not raised again until the cooldown has passed. Tick On to switch the rule on when you save it; a new rule starts off.
Under When it matches, keep Raise an alert (on by default), and add Open a risk in the AI risk register with a Risk category, Request an AI investigation or Open a case as needed. See When a rule matches.
Under Preview, pick a Preview range (Last 24 hours, Last 7 days or Last 30 days) and select Run preview. It shows, window by window, what the rule would have matched, with each group, value and number of events. A preview raises and records nothing. A long range in very short windows is refused; choose a shorter range or a longer window.
Select Create rule (or Save on an existing rule). An enabled rule runs within five minutes. If your organisation requires approval for rule changes, the change is submitted instead and applies once someone else approves it.
Every save is kept in the rule’s version history, with who changed it and when, and is recorded in the audit log. Revert to this version restores an earlier version as a new one.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Detection rules per environment | 200 |
| Filters | 10 per signal (a sequence has up to 10 on each step) |
| Filter value | 500 characters; a regular expression 200 |
| Window | 5 minutes to 7 days |
| Baseline history | 1 to 30 days, and at most 2,016 earlier windows (a 15-minute window can look back 21 days). With Same time in earlier weeks, the window must divide a week evenly and the history must be at least 7 days |
| Baseline threshold | 0.5 to 100 |
| Sequence: second step within | 1 minute to 24 hours of the first |
| First seen: lookback | 1 to 90 days, longer than the window |
| Absence: silent for | 15 minutes to 7 days |
| Absence: having reported in | 1 to 30 days |
| Run every | 5 minutes to 1 day (1,440 minutes); default 15 |
| Cooldown | 0 minutes to 7 days; default 60 |
| Name / description | 120 / 1,000 characters |
| Groups one evaluation returns | 200, worst first |
When a rule matches
Section titled “When a rule matches”- Raise an alert. A
detection.matchalert with the rule’s severity goes to the Alerts inbox and to any channel whose rules route it. Matches of one group in one window are one alert. Its title and text give the rule, the kind of group and the counts (“Sensitive-data blocks spike for one person (27 events)”), never who or what matched. Who or what matched is stored with the alert, in its attributessubjectType(person, machine, model…) andsubject, for the in-app view and the AI analyst, besidegroupKey, a keyed hash that stays the same from run to run, the rule id and version, the value and what it was compared with. Nothing that names who or what matched leaves Shield360: Slack, Teams, email, PagerDuty and webhooks receive thegroupKeyand the counts, never the subject. - Open a risk. One observed risk per group in the AI risk register, in the category you choose. It is refreshed while the group keeps matching and reopens if it matches again after being closed. Its evidence names no person, machine or session, only the group’s keyed hash.
- Request an AI investigation. Marks the alert with
investigate: truefor the AI analyst to pick up. The analyst pseudonymises the subject before anything reaches a model. - Open a case. Each match opens a security case, or adds to the case still open for the same rule and person. The insider-risk templates have it on.
Templates
Section titled “Templates”The Templates tab holds ready-made detections. Each is off until you select Enable, which adds the rule (or switches back on the rule made from it before). You can then open and change it like any other.
| Template | Kind |
|---|---|
| Sensitive-data blocks spike per person | Threshold |
| Sent anyway, repeatedly | Threshold |
| Unapproved model first seen | First seen |
| Spend anomaly per person | Baseline |
| Spend anomaly per model | Baseline |
| New MCP tool first seen | First seen |
| Secret read, then an outbound call | Sequence |
| Collector tampered with, then permissions bypassed | Sequence (on the collector.tamper alert, raised when coding-agent hooks are removed; see Enforcement coverage) |
| Guard gone quiet on a machine | Absence |
| Prompt-injection burst | Threshold |
| Agent retry or loop spike | Threshold |
| MCP tool call, then an outbound call | Sequence (also part of an AI analyst story) |
| Sent anyway, then an unapproved model | Sequence (also part of an AI analyst story) |
How rules run
Section titled “How rules run”A scheduled scan runs every five minutes and evaluates the rules that are due. To keep it bounded, one run evaluates at most 25 rules per environment and 200 in all, raises at most 10 alerts per rule and 50 per environment, and stops starting rules after four minutes; anything left is due on the next run. Every query is limited to its window and to a fixed number of rows and groups. A rule that fails records its error, shown in the list, and never stops the others. Change the scan’s schedule with the DETECTION_SCAN_SCHEDULE environment variable.
Permissions
Section titled “Permissions”| To | You need |
|---|---|
| See detection rules, their templates and previews | View computers and people, and the permission of each signal a preview reads |
| Create, change, switch on or off, and delete rules | Configure the rule engine, and the permission of each signal the rule reads |
Detection rules can be managed over HTTP with a signed-in session or a Shield360 API key (Settings → Developer → Shield360 API keys); a key acts with its creator’s permissions. Every request acts on the environment (database configuration) your session or key resolves to; a config id in the body is never used. Responses are { "data": … }, or { "err": "…", "detail": { "code": "…", "path": "…" } } on an error, where code and path name what was wrong (for example bad_number at windowMinutes). A body that is not valid JSON is refused with 400.
| Method and path | Permission (key) | Does |
|---|---|---|
GET /api/rule-engine/detections | View computers and people (collector.read) | Every rule with its run state, the signal catalogue (names, fields and types, and whether you may build on each), and whether you may change rules |
POST /api/rule-engine/detections | Configure the rule engine (rule_engine.configure) | Adds a rule; 201 with the rule |
GET /api/rule-engine/detections/<id> | collector.read | One rule, its run state and version history |
PATCH /api/rule-engine/detections/<id> | rule_engine.configure | Changes any of its fields; what you leave out keeps its value. { "enabled": false } switches it off |
DELETE /api/rule-engine/detections/<id> | rule_engine.configure | Removes the rule, its history and cooldowns. Alerts it raised stay |
POST /api/rule-engine/detections/<id>/revert | rule_engine.configure | { "version": 3 } restores that version as a new one |
POST /api/rule-engine/detections/preview | collector.read | { "definition": {…} } or { "ruleId": "…" }, with "range": "24h" (default), "7d" or "30d". Raises and records nothing |
GET / POST /api/rule-engine/detections/templates | collector.read / rule_engine.configure | Lists the templates; { "key": "…" } enables one |
Saving or previewing also needs the permission of every signal the definition reads (403 otherwise).
A rule’s body takes name (required), description, severity (info, warning or critical; default warning), enabled (default false), definition, actions, scheduleMinutes (default 15) and cooldownMinutes (default 60). Any other field is refused. The definition has a kind and that kind’s fields: signal, filters ({ field, operator, value }), aggregate ({ fn: "count" | "sum" | "distinct" | "rate", measure?, dimension? }), groupBy, comparator (gt, gte, lt, lte), value and windowMinutes for a threshold; historyDays, seasonality (none or hour_of_week), method (ratio or zscore), threshold and minVolume for a baseline; subject, first, then and withinMinutes for a sequence; field and lookbackDays for first seen; silentMinutes and expectedDays for absence. actions takes alert (default true), risk: { enabled, category }, investigate and case.
curl -X POST https://<shield360>/api/rule-engine/detections \ -H 'Content-Type: application/json' -H 'Authorization: Bearer <Shield360 API key>' \ -d '{ "name": "Sensitive-data blocks spike per person", "severity": "warning", "enabled": true, "scheduleMinutes": 15, "cooldownMinutes": 240, "definition": { "kind": "threshold", "signal": "guard_decisions", "filters": [ { "field": "category", "operator": "equals", "value": "sensitive_data" }, { "field": "outcome", "operator": "equals", "value": "blocked" } ], "aggregate": { "fn": "count" }, "groupBy": "person", "comparator": "gt", "value": 20, "windowMinutes": 60 }, "actions": { "alert": true, "investigate": true } }'Signal keys are guard_decisions, injection_detections, policy_violations, usage, site_activity, app_activity, network_observations, browsing_visits, collector_heartbeats, agent_tool_calls, openshell_decisions, agent_actions, alert_events, audit_events and inventory_assets; the GET response lists each one’s fields and groupings.
Rule changes follow your organisation’s change control (Govern → Policies & rules → Policy changes): a create, change, delete, revert or template enable may carry a changeComment, a change freeze answers 423, and when approval is required the answer is 202 with the pending change, which applies only once someone else approves it.
Frequently asked questions
Section titled “Frequently asked questions”Do detection rules change how match rules work?
No. Match rules are evaluated per request exactly as before, by evaluations, prompts, contexts and the governance report. Detection rules are stored and run separately.
Why did a baseline rule not fire on a new person?
A baseline needs a norm: at least three earlier windows with something in them. Someone new has no history to compare with. Use a threshold rule for absolute limits.
What does the estimated cost in AI usage mean?
Tokens priced at the list prices in Manage Models for each model, as the Costs report’s API-equivalent figure. Usage covered by a subscription seat is priced the same way, so it measures how much was used, not what was billed.