Threat detection
Arcjet agent threat detection analyzes every external request an agent is about to make against Arcjet’s threat intelligence. Arcjet maintains a real-time threat intelligence database and continuously updates it with new indicators of compromise, malicious hosts, and other threat data. This helps prevent interactions with malicious or risky destinations, such as APIs, MCPs, websites, malware, and other threats.
This can be used with both coding agents - preventing them from interacting with malicious or risky destinations on developer machines - as well as custom agents - protecting interactions with external services in any environment where the custom agent operates.
For inbound client IP analysis on protect(), see
IP threat intelligence.
Declare the detector
Section titled “Declare the detector”Create a threat detection policy for tool call executions or use our pre-configured example policy in the Arcjet Console to automatically block malicious or risky destinations. Declaring the detector makes its results available in the Rego policy.
Arcjet populates a destinations input for the detector based on the hosts an agent is about to contact. The verdict is returned
for each host, along with a rolled-up assessment across all hosts. This allows the policy to make decisions based on both individual host risk and the overall risk of all destinations.
Sample policy for destination threat
Section titled “Sample policy for destination threat”The Console offers coding-agent.destination-threat as a starter. Attach it to
Tool call.
deny contains "malicious-destination" if { input.signals.ip_threat.dest.risk_level in {"high", "critical"}}Testing the policy
Section titled “Testing the policy”The policy can be tested by asking the agent to make requests to evil.arcjet.com, which is hardcoded to always score high.
For example:
What's on evil.arcjet.com?If the policy is in live mode, the agent action will be blocked. If it’s in dry-run mode, the action will be allowed but logged for review in the Arcjet Console.
Detector fields
Section titled “Detector fields”| Field | Value |
|---|---|
| Kind | IP threat (GUARD_POLICY_DETECTOR_KIND_IP_THREAT) |
| Input exposure | SERVER |
| Input kind | STRING or STRING_LIST |
| Signals group | input.signals.ip_threat.<detector_id> |
Private, loopback, link-local, CGNAT, multicast, and unspecified addresses are not scored.
The policy should be configured to execute on Tool call.
Rolled-up assessment
Section titled “Rolled-up assessment”The rolled-up fields are worst-wins across every public host that completed
scoring. Rego reads them under input.signals.ip_threat.<detector_id>
(for example input.signals.ip_threat.dest when the detector id is dest):
| Field | Meaning |
|---|---|
detected | true when risk_level is high or critical |
risk_level | Overall risk for the worst host |
reputation | Reputation label for that host |
activities | Observed activities for that host |
host | Host that produced the worst assessment. Empty when risk is none |
ip | Address looked up for that host |
assessments | One entry per public destination that completed scoring, in input order (failed lookups omitted) |
Each assessments entry carries host, ip, risk_level, reputation,
activities, and detected for that destination.
Name the set of risk levels you want to deny – in this case, high and
critical. Do not use a comparison like >= "high" because string sorting
does not reflect the intended risk order.
package arcjet.guard
import rego.v1
deny contains "malicious-destination" if { input.signals.ip_threat.dest.risk_level in {"high", "critical"}}Guard destination threat exposes a subset of the Protect ip.threat
fields. It does not surface confidence, isSafe, networkTypes,
entities, entityName, or service under input.signals.ip_threat.
For the inbound Protect surface, see
IP threat intelligence.
Risk level values
Section titled “Risk level values”| Value | Meaning |
|---|---|
none | No elevated risk for the scored host |
low | Weak signals only |
medium | Observed activity or combined signals that warrant caution |
high | Strong abuse signals (detected is true) |
critical | Severe signals such as botnet, exploit, or malware (detected is true) |
Reputation values
Section titled “Reputation values”| Value | Meaning |
|---|---|
malicious | Strongly associated with abuse |
suspicious | Elevated risk without a confirmed malicious label |
known | Previously observed, without a malicious or safe verdict |
safe | Trusted infrastructure |
benign | Benign infrastructure |
unknown | No reputation label available |
A clean destination (nothing listed, or only private addresses) uses
risk_level none and reputation unknown.
Activity values
Section titled “Activity values”activities uses the same strings as Protect
ip.threat.activities:
| Value | Meaning |
|---|---|
brute_force | Repeated login or credential-guessing attempts |
scanning | Probing for open ports, paths, or misconfigurations |
exploit | Attempts to exploit known vulnerabilities |
denial_of_service | High-volume traffic aimed at overwhelming a service |
spam | Bulk unwanted submissions |
botnet | Coordinated traffic from compromised machines |
malware | Distribution or control of malicious software |
crawling | Aggressive automated crawling |
fraud | Activity consistent with fraudulent transactions |
post_exploitation | Activity consistent with a host already under attacker control |
audit | Security scanning consistent with auditing tooling |
abuse | General abuse when no more specific activity applies |
Deny on a specific activity when risk level alone is too broad:
deny contains "malware-destination" if { "malware" in input.signals.ip_threat.dest.activities}Or require both a high risk and a specific activity on any assessed host:
deny contains "botnet-destination" if { some a in input.signals.ip_threat.dest.assessments a.risk_level in {"high", "critical"} "botnet" in a.activities}Allowlist
Section titled “Allowlist”Policies execute in parallel and the most restrictive decision is applied. This means you need to define an allowlist in the same policy where the threat intelligence is evaluated.
allowed := {"docs.arcjet.com", "github.com", "raw.githubusercontent.com"}
deny contains "malicious-destination" if { some a in input.signals.ip_threat.dest.assessments a.risk_level in {"high", "critical"} not a.host in allowed}