Lesson 2 asked whether a visitor is hiding. This lesson asks a different question: has this address, or this domain, already been caught doing something bad? That is reputation, and it comes from blocklists that security teams and volunteer projects maintain by watching attacks happen.
Reputation is useful in two places. On the way in, it scores the address a request comes from: an IP that spent last week brute-forcing SSH servers deserves more scrutiny on your login form. On the way out, it protects your users from each other: if your product lets people post links in comments, messages, profiles or support tickets, someone will eventually post a phishing page, and your domain will be the one that delivered it.
Reputation is history, not identity
Every blocklist entry records that an address or domain was seen doing something at some point. Three things weaken that record over time, and your code has to account for all of them.
- Addresses are reassigned. A residential ISP hands the same address to different subscribers over weeks. A cloud provider hands a released server address to the next customer within minutes. The new holder inherits the old one's listing.
- Addresses are shared. Behind carrier-grade NAT, one infected phone can get an address listed that thousands of other phones also use. Corporate networks and universities have the same problem at smaller scale.
- Domains are cleaned up, or not yet listed. A compromised WordPress site may host a phishing kit for two days, get listed, get cleaned and stay listed for a while. A brand-new phishing domain registered this morning is on no list at all.
The practical consequence: a blocklist hit raises the risk of a request; it does not establish guilt. A clean result fails to raise it; it does not establish safety. Weight both accordingly.
Check an IP against blocklists
IP Blacklist Lookup (ipblacklistlookup) takes an ip on a GET and costs 10 credits. Try it on the example from its definition, a well-known Tor exit:
curl "https://api.apiverve.com/v1/ipblacklistlookup?ip=185.220.101.1" \
-H "x-api-key: YOUR_API_KEY"isIPBlacklisted is on every plan. inbound, outbound, threatLevel and isTor are premium.
Every plan gets ipAddress and the one boolean that matters most, isIPBlacklisted. Higher plans break it down:
| Field | Plan | Meaning |
|---|---|---|
isIPBlacklisted | all | Listed on any of the blocklists checked |
inbound.found | premium | Listed as a source of attacks: spam, scanning, brute force |
outbound.found | premium | Listed as a destination: command-and-control server, malware host, phishing |
threatLevel | premium | Overall severity; none for a clean address. The Tor exit above returned critical |
isTor | premium | Whether the address is a Tor exit |
ipDetails, asn, asnName | premium | Geolocation and network, as in lesson 1 |
The inbound and outbound split is worth understanding even if your plan only has the boolean, because it tells you which direction the risk runs. For a visitor hitting your login form, inbound is what matters: this address attacks things. For a server that a user's link points to, outbound is what matters: this address hosts things that hurt people. The Tor exit above is listed both ways, which is common for exits, since some of the traffic leaving them is abuse.
A clean address, such as Google's resolver 8.8.8.8, returns isIPBlacklisted: false with threatLevel: "none" and null for both inbound and outbound.
Cache blocklist results for a few hours. Lists update continually, and an address that was cleaned up should not stay penalised in your system for a week because of your cache.
Your login endpoint sees a request from an address with isIPBlacklisted: true. On review, the address belongs to a large mobile carrier. What is the sensible response?
Answer the check above to continue.
What to do with a hit
Reject quietly, but tell the poster. For a listed domain, refuse the post with a plain message: "One of the links in your message points to a site reported for phishing." Most people who post such a link were themselves fooled; telling them helps. Do not explain your thresholds.
Hold, do not delete. Structural flags and failed checks go to a moderator with the findings attached. A punycode link to a legitimate site in a non-Latin script is perfectly normal for some communities; a human makes that call in seconds.
Render user links defensively regardless. Even links that pass should not borrow your domain's authority:
<a href="https://example.org/article" rel="ugc nofollow noopener noreferrer" target="_blank">example.org/article</a>ugc and nofollow tell search engines the link is user content you do not vouch for; noopener stops the opened page from controlling your tab. Showing the real host as the link text, rather than whatever text the user chose, defeats the oldest trick in phishing.
Re-scan what you already published. A link that was clean when posted can be listed a week later. Re-check hosts from recent content on a schedule, newest first, and unpublish anything that turns up. The six-hour cache keeps that affordable, since the same few hosts recur across many posts.
Privacy and fairness
Blocklists are run by third parties with their own criteria. If a customer's server address is listed because a previous tenant misbehaved, your policy should give them a way out: a support path, an allow-list entry after review, or a step-up they can pass. Log the specific signal behind every decision so that path is possible. Scanning content that users post publicly is ordinary moderation; scanning private messages deserves a line in your terms and privacy notice saying you check links for security.
The last lesson moves from the network to the client itself: what the user agent claims, how to tell a crawler from a browser, and how to combine everything from this course into one decision. Continue to Bots and user agents.