At 05:34 UTC on 19 October 2026 we ran three addresses through the same pipeline and got three different verdicts. A Mullvad VPN exit scored 100, block. A verified AhrefsBot address scored 59, step_up, because Spamhaus lists it. A DigitalOcean server scored 12, allow. Eleven days earlier, that same AhrefsBot address scored 23, allow.
Below are the twelve checks in order, the field to read at each, the thresholds we act on, where to report abuse, and the legal limit of any IP investigation.

How to investigate an IP address: three addresses, three verdicts
The same twelve questions sent three addresses to three different actions, and in each case one signal decided it. These are keyless lookups from our API, saved at the times shown, values unedited:
| IP | What it is | Saved (UTC) | fraud_score, recommended_action | The signal that decided it |
|---|---|---|---|---|
| 185.213.155.73 | Mullvad server de-fra-wg-001, Frankfurt | 05:34:30 | 100, block | On Mullvad's own server list, wireguard_open fired |
| 5.39.1.230 | AhrefsBot, on OVH in Paris | 05:34:32 | 59, step_up | Verified crawler, but listed on Spamhaus ZEN |
| 104.248.50.21 | DigitalOcean droplet, North Bergen, NJ | 05:34:35 | 12, allow | Hosting only, no abuse or anonymizer flag |
Our bands are allow up to 25, review up to 50, step_up up to 75 and block above 75. The order of checks is: routable, owner, network type, hostname, anonymizer, crawler or scanner, blocklists, score, decision, report, expiry and the legal limit.
The middle row is the lesson. A verified crawler can still sit on a blocklist, and the crawler discount in our score did not keep it at allow.
Before you start: stay passive and record where the IP appeared
Write down the alert context before you look anything up: the timestamp with its time zone, the port or path it touched, and what it did, such as probes for /wp-admin or /.env or a burst of failed logins. That context decides the verdict as much as any lookup does.
Stay passive: use lookups, registries and reputation sites, and never scan the address back. A port scan can tip off whoever runs the host, and scanning a network without permission may break the law or your provider's terms.
Step 1: Is it a routable public address?
Check that the address could have reached you over the internet at all. Read threat.is_bogon and threat.is_cgnat. A bogon is an address that should never appear on the public internet, such as a private or reserved range. If one shows up as the source on your internet edge, you are looking at internal traffic, a misconfigured proxy or a spoofed packet, and the rest of this pipeline does not apply.
A carrier-grade NAT (CGNAT) address is routable but shared. One mobile or broadband address can carry hundreds of subscribers at once, so anything you decide about it lands on all of them.
All three of our addresses returned is_bogon false and is_cgnat false, so they continue down the pipeline.
Step 2: Who owns it? ASN and RDAP
The owner comes from two records: the autonomous system (AS) that announces the address, and the registry record for the block. Read asn.asn, asn.org and asn.rpki for the route, then whois.org, whois.netname, whois.registered and network.abuse_contact for the registration.
| IP | asn.asn, asn.org | rpki | whois.org | whois.netname | whois.registered |
|---|---|---|---|---|---|
| 185.213.155.73 | 39351, ESAB-AS - 31173 Services AB | valid | 31173 Services AB infrastructure in Frankfurt, DE. | NET-31173-185-213-155-0-24 | 2017-07-19 |
| 5.39.1.230 | 16276, OVH - OVH SAS | valid | Failover IPs | OVH-DEDICATED-FO | 2012-05-15 |
| 104.248.50.21 | 14061, DIGITALOCEAN-ASN - DigitalOcean, LLC | unknown | none | none | 2018-08-06 |
Notice what the records do not say. Nothing in the Mullvad server's record says "Mullvad": it names 31173 Services, the company that runs Mullvad's network, and whois.has_vpn_keywords is false. DigitalOcean's whois.org came back "none", so the ASN carries the ownership there. Here is what an ASN tells you about the network if you need the background.
When the stored record is thin, go to the source. Registration data lives at the five regional internet registries: ARIN, RIPE NCC, APNIC, LACNIC and AFRINIC. IANA's RDAP bootstrap file tells you which one holds a range. RDAP is the structured, JSON successor to WHOIS. When we opened RIPE's RDAP record for 5.39.1.230 at 05:43 UTC, it showed a smaller block, 5.39.1.224/27, whose registrant organisation names Ahrefs Pte Ltd. Our stored record reflects OVH's larger failover block. The most specific registry record wins.
Step 3: What kind of network is it?
Network type frames every later signal, so read it before any reputation data. The fields are asn.asn_type, asn.user_type, asn.connection_type, detection.is_hosting and detection.is_mobile.
| IP | asn_type | user_type | connection_type | is_hosting | is_mobile |
|---|---|---|---|---|---|
| 185.213.155.73 | hosting | hosting | datacenter | true | false |
| 5.39.1.230 | hosting | search_engine_spider | datacenter | true | false |
| 104.248.50.21 | hosting | hosting | datacenter | true | false |
All three are hosting addresses, and only one ended at block. Hosting is context, not guilt: VPN exits, crawlers and your own CI runners all live in data centers. That is why a hosting IP is not proof of fraud. AhrefsBot's user_type of search_engine_spider is the first hint that the second address is a crawler.
Step 4: What does its hostname say? Reverse DNS and FCrDNS
Reverse DNS returns the hostname the block owner set, and forward-confirmed reverse DNS (FCrDNS) checks that the hostname resolves back to the same IP. Read network.ptr_record and network.fcrdns_valid, then run the check yourself, because a stored PTR can lag live DNS. We ran these at 05:42 UTC on 19 October 2026:
dig -x 185.213.155.73 +short # no answer
dig -x 5.39.1.230 +short # proxy-fr005-cip7.ahrefs.net.
dig +short proxy-fr005-cip7.ahrefs.net # 5.39.1.230
dig -x 104.248.50.21 +short # no answer
The AhrefsBot address passes FCrDNS live, and Ahrefs' robot page says its crawler hostnames always end in ahrefs.com or ahrefs.net. Our API, though, stores no PTR for it, which is why no_ptr_datacenter fires on it later. Trust the live run over the stored field.
The DigitalOcean server shows the other failure. Our API stores a hostname for it that belongs to an unrelated third party, fcrdns_valid is false, and the fcrdns_mismatch method fires. Our own dig -x returned no PTR at all, so the stored name is stale. A mismatch like this is a weak signal: it was one of only two methods that fired, and the address still scored 12.
Step 5: Is it a VPN, proxy, Tor exit or relay?
This step asks whether someone is hiding behind the address. Read detection.is_vpn, is_proxy, is_tor, is_relay, vpn_provider, relay_provider and last_seen.
| IP | is_vpn | is_proxy | is_tor | is_relay | vpn_provider | last_seen |
|---|---|---|---|---|---|---|
| 185.213.155.73 | true | false | false | false | Mullvad | 2026-10-17T20:32:18.000Z |
| 5.39.1.230 | false | false | false | false | none | 2026-10-18T21:40:52.000Z |
| 104.248.50.21 | false | false | false | false | none | 2026-10-18T10:14:47.000Z |
The Mullvad server is named with vpn_confidence 95 because it is on the server list Mullvad publishes for its own apps. That is how a VPN IP gets matched to its provider, and it has a limit: an unlisted VPN can still be caught by probes but stays unnamed. For Tor, compare the address with the Tor Project's bulk exit list, or read our guide to detect Tor exit traffic. Relays such as iCloud Private Relay are not VPNs: they carry ordinary browser users, so our score caps a relay address at 60 and it can never reach block.
Step 6: Is it a verified crawler or a known scanner?
A verified crawler is an address on its operator's published range list, and a scanner is infrastructure that probes the whole internet. Read threat.crawler.verified, name, operator and verification_method, then threat.is_scanner and threat_types.
| IP | crawler.verified | crawler.name, operator | verification_method | is_scanner | threat_types |
|---|---|---|---|---|---|
| 185.213.155.73 | false | none | none | false | ["vpn"] |
| 5.39.1.230 | true | AhrefsBot, Ahrefs | ip_range_list | false | ["spammer","abusive"] |
| 104.248.50.21 | false | none | none | false | [] |
| 162.142.125.10 | false | none | none | true | ["scanner"] |
AhrefsBot matched Ahrefs' published ranges, so its operator is settled. Anything whose User-Agent claims to be Googlebot deserves the same treatment: verify an IP that claims to be Googlebot before you trust it. The wider picture is in detecting bots by IP address.
The fourth row is a Censys scanner in Ann Arbor, looked up at 05:34 UTC. It returned is_scanner true, a score of 0, allow, and an empty detection_methods list. The scanner flag does not move our score, so read it directly.
Step 7: Is it on blocklists, and since when?
Blocklists record that abuse was seen from an address, and their dates matter more than their presence. Read threat.is_abusive, is_spammer, is_botnet and dnsbl_sources.
| IP | is_abusive | is_spammer | is_botnet | dnsbl_sources |
|---|---|---|---|---|
| 185.213.155.73 | false | false | false | [] |
| 5.39.1.230 | true | true | false | ["zen.spamhaus.org"] |
| 104.248.50.21 | false | false | false | [] |
Then check the outside sources, passively:
- Spamhaus. ZEN combines Spamhaus's free IP blocklists, and its page points to Spamhaus's IP and domain reputation checker for listing details.
- AbuseIPDB. AbuseIPDB shows user-submitted abuse reports. Read its confidence score and the dates of the latest reports, not the total count.
- VirusTotal. VirusTotal shows how many security vendors flag the address and any files or URLs tied to it.
- Shodan and Censys. Shodan and Censys show what their scans already found running on the host, so you see open services without touching it.
Recency beats presence. A listing from last week matters, and a clean result from six months ago tells you almost nothing about today.
Step 8: Read the score and the methods that fired
The score is a dated roll-up of everything above, and scoring.detection_methods tells you why it landed where it did. This is the AhrefsBot lookup, trimmed to the groups this playbook uses, values unedited:
curl https://api.geoiphub.com/v1/lookup/5.39.1.230 -H "x-api-key: YOUR_API_KEY"
{
"ip": "5.39.1.230",
"asn": {
"asn": 16276,
"org": "OVH - OVH SAS",
"asn_type": "hosting",
"user_type": "search_engine_spider",
"rpki": "valid"
},
"whois": {
"org": "Failover IPs",
"netname": "OVH-DEDICATED-FO",
"registered": "2012-05-15T00:00:00.000Z"
},
"network": {
"abuse_contact": "abuse@ovh.net"
},
"detection": {
"is_vpn": false,
"is_tor": false,
"is_hosting": true
},
"threat": {
"is_abusive": true,
"is_spammer": true,
"is_scanner": false,
"threat_types": ["spammer", "abusive"],
"dnsbl_sources": ["zen.spamhaus.org"],
"crawler": {
"verified": true,
"name": "AhrefsBot",
"operator": "Ahrefs",
"verification_method": "ip_range_list"
}
},
"scoring": {
"fraud_score": 59,
"confidence": 0.486,
"recommended_action": "step_up",
"detection_methods": ["abusive_listed", "datacenter_blocklisted", "no_ptr_datacenter", "verified_crawler", "known_spammer"]
},
"meta": {
"last_classified_at": "2026-10-19T05:34:32.660Z"
}
}
The methods for all three addresses:
| IP | Score, action | confidence | detection_methods |
|---|---|---|---|
| 185.213.155.73 | 100, block | 0.7075 | known_vpn_server, wireguard_open, datacenter_with_vpn_proxy, no_ptr_datacenter |
| 5.39.1.230 | 59, step_up | 0.486 | abusive_listed, datacenter_blocklisted, no_ptr_datacenter, verified_crawler, known_spammer |
| 104.248.50.21 | 12, allow | 0.22 | datacenter_ip, fcrdns_mismatch |
verified_crawler is an exonerating signal worth minus 30 in our scoring, and it still was not enough to offset two blocklist methods and a spam listing. Reputation is history, and the score is a snapshot of it; here is how IP reputation is built.
Step 9: Decide whether to block the IP, the prefix or the ASN
Map the score band to an action, then choose how wide the action reaches. These are the verdicts we would act on:
| IP | Our decision | Why |
|---|---|---|
| Mullvad, 100 | Block on signup, payment and admin flows; step up instead where your users legitimately use VPNs | An anonymizer on a sensitive flow, with no user history to weigh against it |
| AhrefsBot, 59 | Allow crawling at a rate limit; step up anything that submits a form or logs in | A crawler has no reason to log in, and its range is currently listed |
| DigitalOcean, 12 | Allow and watch | Hosting alone, nothing else fired |
Scope matters as much as the action. Block one IPv4 address for a one-off. For IPv6, block an IPv6 /64 instead of one address, because one customer usually controls the whole /64. Block a whole ASN only for hosting networks your real users never come from, and never for a mobile carrier or a CGNAT range.
Prefer rate limits and challenges over hard bans: a ban also hits whoever holds the address next week. Automating bans from your logs, for example with fail2ban, is a topic of its own. For which signal stops which attack, see which IP signal stops which attack.
Step 10: Report an abusive IP to its network's abuse contact
Send abuse reports to the address in network.abuse_contact, which comes from the registry record:
| IP | network.abuse_contact |
|---|---|
| 185.213.155.73 | abuse-cust-de@31173.se |
| 5.39.1.230 | abuse@ovh.net |
| 104.248.50.21 | abuse@digitalocean.com |
| 162.142.125.10 | scan-abuse@censys.com |
Send evidence, not adjectives: timestamps with the time zone, the log lines, the destination host and port, and what the traffic did. File it on AbuseIPDB too, so other defenders see it.
Step 11: How long does an IP verdict last?
A verdict lasts days, not months, and we watched one change. On 8 October 2026 we looked up 5.39.1.230 for a post on web scraping. It returned crawler.verified true, is_abusive true, a score of 23 and allow, with the methods abusive_listed, datacenter_blocklisted, no_ptr_datacenter and verified_crawler.
At 05:34:32 UTC on 19 October 2026 the same address returned 59 and step_up. Same crawler, same verified range, same operator. What changed in the methods was known_spammer, which joined the list, and today's lookup shows is_spammer true with zen.spamhaus.org in dnsbl_sources. We did not record those two fields on 8 October, so we know the spam listing is new to the score, not the day Spamhaus added it. The verified-crawler discount still applied, and it was not enough. Eleven days moved the address across two bands.
Our threat feeds and crawler range files both refresh daily, so a verdict can move overnight. The rule: store the date with every verdict, and re-run the lookup before acting on one older than your feed cycle. A flag is not a verdict, and a verdict expires.
Step 12: Can you find the person behind an IP address?
No. An IP address leads you to a network, not a person: only the ISP or host can match an address and a time to a subscriber, and it releases that under legal process such as a court order, not to you or to us.
Investigate addresses that touched your own systems, stop at the network, and do not try to unmask or scan anyone. Geolocation is approximate as well: our three lookups placed the addresses in Frankfurt, Paris and North Bergen, which locates a data center at city level, never a street address.
Run the same pipeline on your next alert
Take the next address from your alert queue and run it through the same lookup with the alert context beside it. To automate the twelve checks, start with the lookup API docs.
Lookups without a key are capped at 30 a minute, and the cap is strict: the 30th request inside one minute already returns a 429 and locks the caller IP out for two hours. Use a free key for scripts: it gives 1,500 lookups a day with every field. Feeding lookups into a SIEM at scale is the next step for a busy queue.
Start Scoring Every IP in Real Time
GeoIPHub gives fraud, security, and engineering teams a single API for IP geolocation, VPN & proxy detection, threat intelligence, and an explainable 0 to 100 risk score.
Get Your Free API Key
Sign up in minutes, no credit card required. Upgrade only when you need more volume.
Frequently Asked Questions
How do you investigate a suspicious IP address?
Work passively, in order. Confirm it is a routable public address, read who owns it and what kind of network it is, check its hostname, anonymizer and crawler flags, read blocklist listings and their dates, then act on a score and write the date down.
How can I check if an IP address is malicious?
No single check proves it. Look for current listings such as Spamhaus, recent abuse reports on AbuseIPDB and anonymizer flags, then weigh them against what the address did on your own systems. A flag means abuse was seen from the address, not that this request is abuse.
Can you find the person behind an IP address?
Not on your own. An IP leads to a network operator, and only that operator can match an address and a time to a subscriber, which it discloses under legal process, not to you. Report abuse to the network's abuse contact instead.
Should I block the IP, the prefix or the whole ASN?
Block one IPv4 address for a one-off, an IPv6 /64 rather than a single IPv6 address, and a whole ASN only for hosting networks your real users never come from. Avoid blocking mobile or CGNAT ranges, because one address can carry many users.
Is a verified crawler always safe to allow?
No. AhrefsBot's 5.39.1.230 matched Ahrefs' published ranges on 19 October 2026 but was also listed on Spamhaus ZEN and scored 59, step_up. Verification tells you who operates the address, not that its range is clean.
How long does an IP investigation result stay valid?
Days, not months. The same AhrefsBot address scored 23, allow, on 8 October 2026 and 59, step_up, on 19 October. Re-run the lookup before acting on an old verdict and store the date with every verdict.