# Threat intel: AbuseIPDB and SniffCat

RemotePower already notices when an address hammers a host with failed SSH
or web logins. Threat intel builds on that. It can:

- **look up** the address with [AbuseIPDB](https://www.abuseipdb.com) and
  [SniffCat](https://sniffcat.com), so you can see whether it's a known
  scanner;
- **report** it back to both services, so other people benefit from what your
  hosts saw;
- **block** it for a while on the host it attacked.

All three are off until you turn them on. You'll find everything under
**Security → Threat intel**.

If you also run a web server, a WAF, fail2ban or CrowdSec, the
[log sensor](#the-log-sensor) lets RemotePower read what those logs say about
each address, so a report says what the address actually did. If you run
Cloudflare or a honeypot, [edge sources](#edge-sources) bring in what they saw
too.

## How it works

1. A host's sshd or web server logs failed logins. The brute-force detector
   counts them per source address. When an address crosses the threshold
   (Settings → Alert parameters), RemotePower raises an alert and queues the
   address for threat intel.
2. Once a minute, RemotePower handles the queue. Private and reserved
   addresses are skipped. It never calls out while an agent is reporting, so a
   slow provider can't hold up your fleet.
3. **Lookup.** Both services are asked for the address's confidence score
   (0–100). The higher of the two is used, along with the report count,
   country and network owner. Answers are reused for 24 hours.
4. **Report.** If reporting is on and the address made at least the number of
   attempts you set (default 10), it's reported to each service at most once a
   day. The categories used are SSH and brute-force for sshd, and web attack
   and brute-force for web logins. An address that is never blocked (see
   [Blocking](#blocking)) is never reported either.
5. **Block.** If blocking is on and the score reaches your threshold (default
   90), the host it attacked gets a firewall rule that drops its traffic. The
   rule is removed again after the hours you set (default 24).

## The log sensor

Out of the box RemotePower learns about an attacker from failed SSH logins and
a few web patterns. The log sensor reads more. Switch it on under
**Security → Threat intel → Log sensor** and the agent on each Linux host
reads these, read-only, once a minute:

| Log | What it tells RemotePower |
|---|---|
| Web server access logs (nginx, Apache) | Requests that look like SQL injection, path traversal, code execution, a scan for exposed files, or login brute force, and whether the server answered them |
| Web server error logs | ModSecurity messages, rate-limit trips, failed basic-auth logins, requests the server refused |
| ModSecurity audit log (native or JSON) | Which rules fired, and whether the WAF blocked the request |
| fail2ban's log | Which addresses it saw failing, which it banned, and in which jail |
| CrowdSec | The alerts its own scenarios raised on this host, including AppSec |
| Firewall log (UFW, kernel `LOG` records) | Addresses the firewall refused on several ports, or many times, within a minute |

The agent finds the files from the web server's own configuration (nginx
`access_log` and `error_log`, Apache `CustomLog` and `ErrorLog`, ModSecurity's
`SecAuditLog`), and reads each one in the layout its `log_format` declares, so
a custom format works without setup. A host with no configuration is covered by
the standard paths. Add anything else under **Extra log files**: up to 20,
each a file under `/var/log`.

### The firewall log

The agent reads `/var/log/ufw.log`, or `/var/log/kern.log` when there is no
UFW log, for records the firewall wrote when it refused a packet. One refused
packet means nothing on a public address, so an address only counts as a scan
when, within one minute, it tried **four different ports** or had **fifteen
packets** refused. Only inbound TCP refusals count. Allowed and audited records,
outbound packets, private source addresses, and UDP and ICMP are ignored. The
source address of an unsolicited packet is whatever the sender wrote, and UDP
and ICMP are what a flood forges, so a report built on them could name its
victim.

The firewall has to log for this to see anything. With UFW that is `ufw logging
low`. A host whose firewall is off, or does not log, shows its log as quiet on
the **Log sources** card, which is true.

The sensor is off by default and works on Linux agents only. It does nothing
to the logs it reads and runs in its own thread, so a slow or broken log can
never delay a heartbeat.

### What is sent

Per address: counts and a short list of fixed labels, such as `SQL injection`,
a WAF rule number, a CVE id the logs named, or the name of a fail2ban jail.
**Log lines, request paths, host names and user names never leave the host.**
The server only keeps what is on its fixed list and drops the rest, so nothing
an attacker typed can reach a report or the page.

### When an address is reported

An address is reported when **any** of these is true:

- fail2ban banned it;
- one of CrowdSec's own scenarios raised a ban on this host (a community
  blocklist entry or a decision someone made by hand does not count);
- the WAF on a host refused its requests as many times as **Report after WAF
  refusals** says (1 by default);
- Cloudflare refused its requests as many times as **Report after Cloudflare
  refusals** says (1 by default, see [Edge sources](#edge-sources));
- it made as many hostile requests as **Report after attempts** says (10 by
  default).

What it does adds up for a day, so a slow attacker still counts. The page says
why an address has not been reported yet and names the nearest of these routes,
for example `4 / 10 attempts so far` or `2 / 3 WAF refusals so far` (when you
have raised the WAF number). An address
with nothing recognisable in the logs is never reported.

### What a report says

The categories follow what was seen:

| Seen | AbuseIPDB | SniffCat |
|---|---|---|
| SSH brute force | 18, 22 | 17, 18 |
| Login brute force (web) | 18, 21 | 17, 21 |
| SQL injection | 16, 21 | 12, 21 |
| Path traversal | 21 | 16, 21 |
| Code execution attempts | 15, 21 | 13, 21 |
| Probing for exposed files | 21 | 21 |
| Attack tools and scanners | 19, 21 | 5, 21 |

Mail, FTP, other services, request flooding and port scans have their own
categories too. The standard message is the same for every report and names the
attack and where it was seen, for example `SQL injection and path traversal: 41
attempts within 10 minutes, seen by web server log and WAF (reported by
RemotePower)`, so it says "brute force" only when that is what happened. You can
write your own (see [The report message](#the-report-message)). For a report
built from the logs, AbuseIPDB also gets the time the attack happened.

An address is reported once per service per sweep, however many hosts or logs
saw it. If a service answers that it was reported moments ago, RemotePower
counts it as reported instead of retrying. **Evidence → Details** on the
Attackers table shows exactly what was sent to each service.

### If fail2ban reports too

fail2ban's own AbuseIPDB and SniffCat actions report each ban on its own. An
address that several jails ban is reported several times, and the services
refuse a second report of the same address within 15 minutes (AbuseIPDB) or 20
minutes (SniffCat). If you let RemotePower do the reporting, turn those actions
off. If you leave them on, nothing breaks: a report the service calls a repeat
is treated as already done.

### Behind Cloudflare or another proxy

If your web server logs the proxy's address instead of the visitor's, every
request seems to come from the proxy. RemotePower ignores Cloudflare's
published addresses and says so on the **Log sources** card, with how many it
ignored. Restore the visitor's address (nginx `real_ip_header`, Apache
`mod_remoteip`) and the real addresses are counted. A web attack that arrives
through a proxy is never blocked on the host, because a firewall rule on the
host would not match it.

### Limits

- An agent sends at most 300 addresses at a time, and a host can add at most
  3,000 an hour, so one host cannot use up your day's reports.
- Each pass reads at most 8 MB of a log. A log seen for the first time is read
  from its last 2 MB, and nothing older than six hours counts.
- A plain web address is sent after 3 hostile requests in a pass, or at once if
  fail2ban, CrowdSec or the WAF flagged it.
- Network work is limited to 25 addresses a sweep, strongest first, so a short
  daily allowance goes to the addresses that earned it.

## Edge sources

Your hosts are not the only place an attack shows up. Cloudflare refuses
requests before they reach your server, and a honeypot catches scanners that no
host log ever sees. RemotePower can read both and report what they show, the same
way it reports what your hosts' logs show.

Reading does not block anything: banning stays with whatever you already use,
such as ModSecurity, CrowdSec, fail2ban or Cloudflare's own rules. Off until you
turn it on, under **Security → Threat intel → Edge sources**. The
[edge blocklist](#the-edge-blocklist) below is a separate card, with its own
switch and its own token.

| Source | What you get |
|---|---|
| Cloudflare firewall events | The requests Cloudflare refused, by address, with the mechanism that refused them |
| Honeypot Worker log | The traps a visitor tripped, and whether your Worker banned the address |

RemotePower asks Cloudflare for counts grouped by address, mechanism and rule.
The request path and the user agent are never fetched, so nothing a visitor typed
can reach a report.

A Free plan has no grouped view. Cloudflare refuses it with `zone '…' does not
have access to the path`, and RemotePower then reads that zone's events one at a
time and groups them itself. It asks for four fields only (address, action,
source and rule), so the path and the user agent stay out here too. Each zone is
asked on its own: a zone Cloudflare refuses is named on the **Edge feeds** card
and does not hold back the others.

### What counts

Only a **refusal** by a mechanism that means "this looked like an attack":

| Counts | Does not count |
|---|---|
| Managed rules, your own custom rules (action block), rate limiting rules, HTTP DDoS protection, Bot Fight Mode, Bot Management, Browser Integrity Check, user-agent block rules | Challenges and log-only actions, country and ASN rules, the security level, IP access rules, and rules that also block an IP list |

The last two are left out for a reason. An IP access rule is a ban that
fail2ban, CrowdSec or your honeypot already decided on, so counting the requests
it blocks would report the same address again. A rule that also blocks an IP
list refuses addresses for being on a community blocklist, which is not
something they did to you. The **Test connection** button lists your custom
rules and marks the ones that name an IP list. If you want them counted anyway,
tick **Count refusals by a rule that also blocks an IP list**.

An address is reported after **Report after Cloudflare refusals** refusals by
Cloudflare, which is 1 unless you change it: the refusal is a block your own
rules or Cloudflare's already made. A host's WAF works the same way with **Report
after WAF refusals**, also 1 by default. A weaker mechanism
(Bot Fight Mode, Browser Integrity Check, a user-agent rule) only counts towards
**Report after attempts**. The reason an address has not been reported yet names
the nearest route, for example `1 of 3 Cloudflare refusals so far`. When you
lower the number, addresses counted in the last day are reported on the next
sweep.

### The honeypot

The honeypot Worker logs every trap hit with its own decision. RemotePower reads
those lines and files each trap under an attack class:

| Trap | Filed as |
|---|---|
| Loot and exploit paths, fake admin pages, private host names, a fake backup tree | Probing for exposed files and admin pages |
| A path only `robots.txt` names | Unwanted web crawling (a bot that ignores `robots.txt`) |
| A crawler claiming to be a search engine from the wrong network | Unwanted web crawling (user-agent spoofing) |
| A credential the honeypot handed out being used | Using a credential planted in a decoy file |
| Signing in to a decoy service | Signing in to a decoy service |

A report from the honeypot reads, for example, `using a credential planted in a
decoy file: 1 attempt within 1 minute, seen by edge honeypot (reported by
RemotePower)`. One built from Cloudflare's events reads `probing for exposed
files and admin pages: 8 attempts within 10 minutes, seen by Cloudflare WAF
(reported by RemotePower)`.

The Worker's own ban counts as a decision, like fail2ban's. An address it banned
is reported at once. Hits it only counted wait for **Report after attempts**.
Addresses the Worker never bans (yours, Cloudflare's shared ones, countries you
exempt) are not reported on its word alone. Lines it logs only to be read, such
as a self-test, are not evidence.

### Set up the edge feeds

[Edge sources: Cloudflare](edge-sources.md) is the step-by-step guide: the token
and its permissions, the account id, Test connection, what each card shows and
what to do when Cloudflare refuses a read. In short: create a read-only token
(Zone: Zone, Analytics and Zone WAF; Account: Workers Observability, for the
honeypot's log), paste it with your account id under **Security → Threat intel →
Edge sources**, press **Test connection**, and tick the switch.

RemotePower reads every ten minutes (every five at the fastest). A read never
goes back further than six hours, as with the host logs, so a pause longer than
that loses what it held. An unticked feed shows as off.

### The edge blocklist

Edge sources reads. The edge blocklist writes one thing: a Cloudflare IP list. It
builds the list from the sources you pick (your own entries, the addresses
RemotePower found, AbuseIPDB's blacklist and SniffCat's blacklist) and keeps it
up to date, so a rule of yours that says `ip.src in $your_list` keeps blocking
what they report. RemotePower never creates or edits a rule.

It is off until you turn it on, and it needs a second token that can edit lists
(Account Filter Lists: Edit). A list it did not create is left alone until you
tell it to take the list over. Its guards, the sources' settings and what to do
when it holds a sync are in
[Edge sources: Cloudflare](edge-sources.md#edge-blocklist).

### If other scripts report the same things

Scripts that report Cloudflare events or UFW blocks to AbuseIPDB or SniffCat
report on their own, usually every hour or two. The services refuse a second
report of the same address within 15 and 20 minutes, and RemotePower counts that
as already reported, so nothing breaks. When the feeds here work, stop those
scripts, so each address is one report with all the evidence. Keep whatever bans.

## Set it up

1. Create API keys:
   - AbuseIPDB: sign in, then **Account → API**. The free plan allows 1,000
     lookups and 1,000 reports a day.
   - SniffCat: sign in, then **API**.

   You can use one service or both.
2. **Security → Threat intel → Providers**: paste the keys and tick what you
   want. Keys are write-only. The page shows that a key is saved, never the
   key itself.
3. Save.

### Limits on API use

Each service has its own daily limits, and you set them on the same page:

| Setting | Default | What it does |
|---|---|---|
| **Lookups per day (each service)** | 900 | Stops asking a service once it has been asked this many times today. |
| **Reports per day (each service)** | 900 | Stops reporting to a service once it has been sent this many reports today. |
| **Reuse a lookup for (hours)** | 24 | How long an answer is kept before the same address is asked about again. |
| **Report after attempts** | 10 | How many failed attempts an address needs before it is reported. |
| **Report after WAF refusals** | 1 | How many requests the WAF on a host must have refused before an address is reported. Raise it if a single refusal is too little for you. |

The defaults stay under AbuseIPDB's free plan of 1,000 a day. Days run in UTC.
When a limit is reached, RemotePower stops until the next day and says so in the
address's row. Use `0` to switch lookups or reports off for that service. The
page shows how many have been used today.

### The report message

Every report carries the standard text unless you write your own in **Report
message** on the same page. The standard text is the same for all of them and
names what was seen:

`{attack}: {count} attempts within {minutes} minutes, seen by {seen_by} (reported by RemotePower)`

A report built from the logs reads `SQL injection and path traversal: 41
attempts within 10 minutes, seen by web server log and WAF (reported by
RemotePower)`. One from the SSH counter reads `SSH brute force: 42 attempts
within 10 minutes, seen by system log (reported by RemotePower)`. One from the
web counter, which counts WordPress login posts and any 401 or 403, reads `web
login attempts and refused requests: 25 attempts within 5 minutes, seen by web
server log (reported by RemotePower)`.

Your own text can use five placeholders:

| Placeholder | Becomes |
|---|---|
| `{attack}` | what was seen, in fixed words: `SQL injection`, `path traversal`, `SSH brute force` |
| `{seen_by}` | which logs saw it: `web server log and WAF` |
| `{count}` | the number of attempts |
| `{minutes}` | the time window, in minutes |
| `{what}` | a short noun: `SSH`, `web login`, `web` or `login` |

For example, `{attack}, {count} attempts in {minutes} minutes` is sent as `SQL
injection, 41 attempts in 10 minutes`. It needs at least 10 characters, because
SniffCat refuses anything shorter, and at most 300. There is no placeholder for
a host name, so one can't end up in a public report by accident. Don't type
one. Clear the box to go back to the standard text.

Before 7.2.0 the box showed `{what} brute force: {count} failed attempts within
{minutes} minutes (reported by RemotePower)` as the default, which called every
report brute force. A Settings page still open from then is read as the standard
text when you save it, not stored as your own wording.

## Ignore what you do not want reported

Some addresses are yours to ignore: a partner's scanner, a monitoring service, a
customer's office. Some kinds of attack are not worth a public report. Two lists
under **Limits and report message** and a button on each attacker say so.

| Setting | What it does |
|---|---|
| **Never report these addresses** | One address or network per line, up to 500, none wider than a /8 (IPv4) or /16 (IPv6). An address on it is never reported to AbuseIPDB or SniffCat. |
| **Never report an address when all it did was** | Tick the kinds of attack. An address is held back when everything it did is a kind you ticked. If it did anything else as well, it is reported as usual. |
| **Ignore** on an attacker's row | Adds that one address to the first list, after asking. It is not shown on an address the list already covers. |

Ignoring only ever does less in public. An ignored address is still recorded and
looked up, and it is blocked when auto-block is on. **Never block or report**,
above, stops that too. The evidence is kept, so taking an address off the list
reports it on its next sighting if it qualifies. A report that was already made
is not taken back.

The status column says `on the ignore list` for an address on the first list and
`not reported: only attacks you ignore` when the second list held it back. The
[edge blocklist](#the-edge-blocklist) still takes high-scoring addresses from the
table, ignored or not: the ignore lists change reporting and nothing else. On a
multi-tenant install only the platform operator can change them.

## What leaves your network

| Action | What is sent |
|---|---|
| Edge read | A request to `api.cloudflare.com` with your read-only token, once every few minutes. Nothing about your hosts. |
| Blocklist sync | Requests to `api.cloudflare.com` with your list token: the list's name, its entries, and a comment on each entry saying which source it came from. Nothing about your hosts. |
| Blacklist download | A request to AbuseIPDB and to SniffCat with your key, at most four a day for each. Nothing about your hosts. |
| Lookup | The attacking address. |
| Report | The attacking address, the attack categories, a one-line comment, and, for a report built from the logs, the time of the attack (AbuseIPDB only). The standard text reads "SQL injection and path traversal: 41 attempts within 10 minutes, seen by web server log and WAF (reported by RemotePower)"; you can change it (see [The report message](#the-report-message)). |

Hostnames, user names, log lines and your own addresses are never sent.

The address is the one sshd logged the connection from, not anything the
client typed. sshd writes the user name a client asks for into the same log
line, before the real address, so a login as `x from 203.0.113.9` puts a
second address in the line. RemotePower reads the last address, the one
followed by `port`.

## Blocking

Blocks run through the normal command queue, so everything that applies to a
person's command applies here too. Nothing is sent to a host in maintenance
mode, quarantine or audit mode, and with four-eyes approval on, a block waits
for a second admin.

On the host, the block uses whichever firewall is active: `ufw`, then
`firewalld`, then plain `iptables` / `ip6tables`. Each rule is tagged
`rp-ipintel`, so you can find it with `ufw status` or `iptables -S`.

These addresses are **never** blocked:

- private, loopback, link-local and other non-public ranges;
- every address your devices report as their own;
- the addresses on your UI IP allow-list (Settings → Security);
- anything on the **Never block** list on the Threat intel page;
- addresses people signed in to RemotePower from in the last 30 days, and
  addresses SSH-gateway sessions came from in that time.

Two limits stop a runaway. A host gets at most 20 automatic blocks an hour,
which you can change. An address one of the services lists as legitimate (its
whitelist) is never blocked.

Blocking needs a Linux agent. You can also block or unblock by hand from the
page, which needs the **command** permission on that host.

### Ban by hand

**Ban** on a row opens a dialog that bans the address in the two places
RemotePower can act: at the edge (the Cloudflare list the
[edge blocklist](#the-edge-blocklist) keeps) and on hosts (the same firewall rule a
block queues, to the hosts that saw it or to every Linux host). They are separate
choices because they stop different traffic: a visitor proxied by Cloudflare
arrives from Cloudflare's addresses, so a rule on a host only stops connections
that reach it directly, and the edge ban is what stops the visitors behind the
proxy. The edge half needs the edge blocklist on with a token and is for the
platform operator; the host half needs the **command** permission on each host and
is skipped for a host that is not a Linux agent you can reach.

Nothing here lifts the protections above: your own hosts, your allow-list, recent
logins, the never-block list, Cloudflare's addresses and private addresses are
refused. A ban lasts 1 hour to 90 days. **Unban** lifts the edge ban and every host
block RemotePower made for that address. The status column says
`in the edge blocklist` for an address the last sync put in your list and
`banned at the edge` for one you banned by hand.

## How much it keeps

Threat intel remembers up to 5,000 addresses. When there are more, the ones seen
longest ago go first. The page is sent the 1,000 most recent and says how many there
are in all when that is more. The filter above the table works on what the page
has, so **Load all** asks for everything that is kept, and the filter can then find
an older address.

Each table draws its first 200 rows and says how many there are. **Show more** adds
200 and **Show all** goes to 1,000, the most the page draws at once. Past that,
filter the list. A filter always starts again from the first 200.

Up to 500 addresses wait to be looked up at a time. When more arrive, an address
that fail2ban, CrowdSec or the honeypot already decided on stays, and the newest of
the rest follow it.

A burst of attacking sources costs one write of the store however large it is, so a
botnet trying your SSH port from thousands of addresses does not hold up the
host's heartbeats.

### Clear the list

**Clear**, above the attackers table, forgets the addresses Threat intel has
recorded and the ones waiting to be looked up. It asks first, and it is for
administrators. On a multi-tenant install a tenant's administrator clears what
their own hosts saw, and the edge's addresses are the platform operator's.

The answer says how many addresses went and how many of each of these it kept:

| Kept | Why |
|---|---|
| Blocks on hosts and bans at the edge | Each expires by itself and has its own **Unblock** or **Unban**. The sweep still lifts what runs out. |
| Addresses the [edge blocklist](#the-edge-blocklist) takes from the table | The list is kept equal to its sources, so forgetting one would take it out of your Cloudflare list at the next sync. Turn off **Found by RemotePower** under **Edge blocklist** first if you want those gone too. |
| The date an address was last reported, for a day | Without it, the next time the address attacks it would be reported again. |
| Settings and keys, the day's counts, where the feeds had read to, and each host's sensor status | They are not addresses. |

An address that attacks again after a clear is recorded again from the start.

## Who can see what

| Role | Sees |
|---|---|
| Admin | Everything, including the provider settings, manual lookups and **Clear**. |
| Anyone else | Attackers and blocks for the hosts their role can see. |

Under multi-tenancy, only the platform operator can change the provider
settings or run a manual lookup, which spends the install's daily quota.

## Troubleshooting

| You see | Meaning |
|---|---|
| No attackers appear | Brute-force detection is off, the threshold is never reached, or the host's sshd/web logs aren't being watched. |
| `API key rejected` | The key is wrong or was revoked. Paste it again. |
| `refused by the provider (HTTP 403)` | The service or its firewall refused the request. This is not a verdict on your key; a wrong key shows as `API key rejected`. Try again later, and check the service's status page if it keeps happening. |
| `rate limited` | The service's daily or per-minute limit was hit. RemotePower tries again on the next attack. |
| `already reported a moment ago` | The service had the same address from you minutes earlier, often from fail2ban. Nothing is wrong. |
| `rate limited or already reported` | SniffCat uses one status for its own limit and for a repeat, and only a repeat says so in words (that case shows as `already reported a moment ago`). When the message does not say, RemotePower cannot tell which it was, and waits a little over 20 minutes before asking again. |
| `not reported: 4 / 10 attempts so far` | The logs show the address, but not enough yet. See [When an address is reported](#when-an-address-is-reported). |
| `not reported: 2 / 3 WAF refusals so far` or `... Cloudflare refusals so far` | The same, counted on the nearest route: the WAF needs the number in **Report after WAF refusals**, and Cloudflare needs the number in **Report after Cloudflare refusals**. |
| `not reported: nothing recognisable in the logs` | Only a jail such as `recidive` named it, so there is no honest category to report it under. |
| Log sources: `Quiet` | The agent looked at the log and nothing new had been written. It looks about once a minute and reads only what was added since the last look, so a log that is written to now and then shows `Quiet` between writes. |
| Log sources: `Reading` | New lines arrived since the last look. The numbers beside it are for that look, not totals. |
| Log sources: `File missing` | The configuration names a log that does not exist yet. |
| Log sources: `No permission` | The agent cannot read the file. It runs as root normally, so check how it was started. |
| Log sources: `Not understood` | Most lines did not match the log's format. Check the `log_format` and that it prints the address, the request and the status. |
| Log sources: `Cannot be read` | fail2ban logs to syslog or the journal, or ModSecurity writes one file per transaction. Log to a single file. |
| Edge feeds: `Refused by Cloudflare` | Cloudflare refused the firewall events for a zone, grouped and one by one. The line names the zone. Check that the token has **Zone → Analytics → Read** and that its zone list includes that zone. |
| Edge feeds: `Reading`, with a note that the events are read one at a time | Expected on a Free plan. The grouped view is refused, so each event is read and grouped here. A read carries up to 2,500 events per zone. |
| Edge feeds: `No permission` | The token cannot read that. **Test connection** shows which check failed; add the permission listed under [Set up the edge feeds](#set-up-the-edge-feeds). |
| Edge feeds: `Needs an account id` | The honeypot's log is read through the account. Paste the account id. |
| Edge feeds: `No zones found` | The token sees no zone. Check it is for all zones of the account, or list the zones you want. |
| Edge feeds: events set aside as `a rule that also blocks an IP list` | Expected: those rules are not evidence. See [What counts](#what-counts). |
| `not blocked: seen at the edge only, so there is no host to block it on` | The address was seen by Cloudflare or the honeypot and by none of your hosts, so there is no host where a block could go. Whatever bans it (Cloudflare, CrowdSec, fail2ban) does it, and the [edge blocklist](#the-edge-blocklist) can hand it to a Cloudflare rule. An address that a host also saw shows that host's reason instead. |
| `not blocked: score 40 is below 90` | The address isn't bad enough for your threshold. |
| `not blocked: on the never-block list` | The address is one of yours, on an allow-list, or someone recently signed in from it. |
