Skip to main content
Static firewall rules catch the calls you knew to name. They can’t catch the call that’s individually allowed but wrong in aggregate — 200 db.query calls at 3am Sunday, an agent hammering one failing tool in a tight loop, a tool-to-tool hop this workspace has never made before. Each call passes every rule; the pattern is the problem. Firewall anomaly detection is the behavioral layer. The gateway learns your workspace’s normal tool-use shape and scores live activity against it, surfacing the deviations on a feed any Member can read. It’s how you notice a compromised agent or a runaway loop without having pre-written a rule for a shape you’d never seen. This page is the focused landing for that firewall anomaly detection feed; the Firewall overview is the deep reference.
The anomaly feed is detection, not enforcement. It tells you what looks off — it does not block. When a pattern is real, you turn it into a rule or a rate-limited verdict so the next occurrence is stopped inline. Reading the feed is open to every Member; turning a finding into policy is Developer+.

1. What firewall anomaly detection flags

Four signal kinds, each tied to a different failure mode:
Per-tool call volume scored against a learned hour-of-week baseline. A tool fires rate_spike when its count clears an absolute floor and runs high relative to the baseline for that hour, or when its z-score crosses the threshold. Keying on hour-of-week (not hour-of-day) means Tuesday-14:00 is compared to past Tuesday-14:00s, so legitimate weekday-peak traffic doesn’t read as a spike while the same volume at 3am Sunday does.
The same hour-of-week comparison, applied to accumulated cost rather than call count. A tool whose spend runs well over its learned cost norm surfaces as a burn_spike — the early-warning signal for an agent that’s expensive before it’s destructive.
A (conversation, tool, arguments) group that repeats many times inside a short window — an agent stuck re-issuing the same failing tool call instead of recovering. Slow, legitimate polling doesn’t trip it; the signal is a tight loop.
A tool_a → tool_b consecutive transition this workspace has no learned baseline for. The first time an agent goes, say, crm.read → http.fetch, that edge is novel — exactly the kind of step a data-exfiltration chain takes.
Anomaly detection complements sequence rules. A sequence rule matches a chain you defined in advance; novel_path flags a transition you didn’t — it’s how you discover the chains worth writing a sequence rule for.

2. The 14-day baseline

The detector isn’t a fixed threshold — it’s a learned norm. For each (tool, hour-of-week) bucket the gateway keeps a rolling expected call-count and cost, backfilled from a 14-day lookback (about two occurrences of each hour-of-week bucket — enough to smooth a single odd day without losing the weekly shape). novel_path uses the parallel transition baseline: the learned occurrence count for each tool_a → tool_b edge in that hour-of-week. A brand-new workspace has no baseline yet. That’s fine: with no learned norm, the volume detectors fall back to an absolute floor, so an obvious flood is still caught on day one while the per-hour norms fill in.
SignalWhat it learns from
rate_spike / burn_spikePer-(tool, hour-of-week) count and cost, 14-day rolling.
novel_pathPer-(tool_a → tool_b, hour-of-week) transition count.
retry_loopNo baseline — a windowed repeat threshold on (conversation, tool, args).
The feed reports tool names, redacted token ids, and counts only. A raw API-key id never appears — each item carries a one-way digest of the calling token, so you can tell two anomalies apart without the feed ever leaking the key behind them.

3. One concrete read

Say an agent key starts looping. Pull the feed in the console under Security → Firewall → Anomalies, or read it directly — any Member can:
curl https://api.orcarouter.ai/api/workspace/firewall/anomalies \
  -H "Authorization: Bearer $ORCA_SESSION_TOKEN"
{
  "data": {
    "items": [
      {
        "id": "3f1c9a7b0e2d4a86",
        "kind": "retry_loop",
        "tool_name": "db.query",
        "token_id_redacted": "sk-***-9f2a",
        "count": 412,
        "baseline": 0,
        "z_score": 0,
        "suggested_action": "rate_limit",
        "first_seen": 1749470400,
        "last_seen": 1749470520
      }
    ],
    "snoozed_until": 0
  }
}
A retry_loop item carries no baseline or z_score (those fields stay 0 — they belong to the volume/cost detectors), and it carries a stable opaque id so two distinct loops on the same tool don’t collide on one row. A rate_spike is the inverse: it reports a learned baseline and a z_score, and leaves id empty.
$ORCA_SESSION_TOKEN is your console session / access token — the same auth as every /api/workspace/firewall/* management route. It is not a relay sk-orca-… key (those are only for /v1/* model calls) and not a firewall-gateway key. A relay key on this route gets rejected.
Each item names the tool, the redacted token, how many calls fired, the z-score (volume/cost signals only), and a suggested_action (rate_limit, block_tool, or review). From here you act: drop a deny rule on the tool, validate its arguments, or open the events log to see exactly what the agent did.

4. Snoozing the feed

A known load test or a planned backfill will light the feed up. Rather than chase noise, snooze it — for up to 7 days:
curl -X POST https://api.orcarouter.ai/api/workspace/firewall/anomalies/snooze \
  -H "Authorization: Bearer $ORCA_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"until": 1749643200}'
While a snooze is active the feed returns no items and reports snoozed_until; it clears itself the moment the deadline passes. The cap is a hard ceiling — a fat-fingered or hostile until further out is clamped so anomaly detection can’t be silenced indefinitely. Posting a past or now until clears an existing snooze.
Reading the feed is a Member action; snoozing it is Developer+ — muting a workspace-wide safety signal is a write, not a read.

5. RBAC at a glance

The analytics surface splits along the usual read/act line:
ActionRole
Read the anomaly feedMember
Read settings, policies, discovered toolsMember
Snooze the feedDeveloper+
Events, runs, aggregate, traceDeveloper+
Author a rule from a findingDeveloper+
The lighter aggregate views — settings, policies, and the discovered-tools coverage map — are Member reads too; the row-level events and runs detail is Developer+, because it carries per-call argument data.

6. From signal to policy

The feed is the start of a loop, not the end:
1

Spot the pattern

A novel_path or rate_spike shows a shape you didn’t expect. Read it against the events log to confirm it’s real, not a one-off.
2

Write the rule

Turn the finding into enforcement — a block, an argument clause, a sequence rule for the chain, or a cost cap for the burn.
3

Roll it out safely

Land the rule under shadow mode first so you measure its blast radius before it blocks a single call, then enforce.

Where to go next

Firewall overview

The full anomaly-detection reference and the rest of the policy plane.

Events log

Drill from an anomaly into the exact calls behind it.

Block a tool

Turn a finding into an enforcing rule.

Enforcement modes

How detection, audit, shadow, and enforce fit together.
For the threats these signals expose, see data exfiltration and excessive agency.