DEV Community

IP99
IP99

Posted on

Don't Ban on hosting or mobile: Network Attributes Aren't Risk Verdicts

If your first IP rule is "block anything with hosting in the response," you will lock out Google Public DNS, most CDNs, CI runners, monitoring agents, and a large share of legitimate VPN egress — while still missing the residential proxy exits that dominate today's supply. IP99 by ThreatHunter returns both network attributes and risk signals in the same JSON. They look similar in an array. They are not the same thing.

This walkthrough stays on the free, no-key GET /v1/ip/{ip} endpoint. Live samples were captured on 2026-11-01 (UTC).

Two kinds of slug in risk.signals

IP99 lists up to ten slugs under risk.signals. Official docs split them:

Slug Kind Participates in score?
proxy, vpn, dialup_pool, hijacked_proxy, osint, cloud_service, cloud_phone Risk observations Yes (when evidence is fresh)
crawler Benign crawler egress No
hosting, mobile Network attributes derived from scene No

hosting means the address sits in datacenter / CDN / Anycast-style space. mobile means cellular. Neither is a proxy verdict. IP99's own copy is blunt: do not ban on hosting or mobile alone — that is how you cut whole clouds and whole carrier ranges. There is no Tor signal; do not invent one.

network.usage_type is the machine-readable scene code behind those attributes (IDC, CDN, DYN, MOB, GTW, EDU, …). Read it as context, not as guilt.

Example A: famous resolver, hosting, score 0

curl https://ip99.com/v1/ip/8.8.8.8
Enter fullscreen mode Exit fullscreen mode

Captured ~2026-11-01 13:06 UTC:

{
  "ip": "8.8.8.8",
  "computed_at": "2026-11-01T13:06:01Z",
  "evidence_state": "none",
  "geo": {
    "continent": "NA",
    "country": "US",
    "region": "California",
    "city": "Mountain View",
    "district": "",
    "tz": "America/Los_Angeles"
  },
  "network": { "asn": 15169, "usage_type": "IDC" },
  "risk": {
    "score": 0,
    "level": "none",
    "signals": ["hosting"]
  }
}
Enter fullscreen mode Exit fullscreen mode

usage_type: IDC and signals: ["hosting"] only say "this lives in hosting space." evidence_state: none with score 0 means IP99 holds no current verifiable risk evidence — not "safe," and not "block." The score measures freshness and strength of risk evidence; it is not the probability that an address is an attacker.

Example B: CDN edge, same pattern

curl https://ip99.com/v1/ip/104.16.132.229
Enter fullscreen mode Exit fullscreen mode

Captured ~2026-11-01 13:07 UTC (abbreviated):

{
  "ip": "104.16.132.229",
  "evidence_state": "none",
  "network": { "asn": 13335, "usage_type": "CDN" },
  "risk": { "score": 0, "level": "none", "signals": ["hosting"] }
}
Enter fullscreen mode Exit fullscreen mode

CDN space is hosting-shaped. Partners, browsers, and APIs terminate here every day. A hosting-only rule treats Cloudflare (and peers) like a proxy farm.

Example C: residential scene with proxy-class evidence

Public demo address often used in IP99 docs (residential dial-up / proxy supply). Full address works in curl; tickets should mask the last octet.

curl https://ip99.com/v1/ip/27.22.66.200
Enter fullscreen mode Exit fullscreen mode

Captured ~2026-11-01 13:06 UTC (last octet masked in the body):

{
  "ip": "27.22.66.x",
  "computed_at": "2026-11-01T13:06:56Z",
  "evidence_state": "active",
  "degraded": true,
  "geo": {
    "continent": "AS",
    "country": "CN",
    "region": "Hubei",
    "city": "Xiangyang",
    "district": "Yicheng",
    "tz": "Asia/Shanghai"
  },
  "network": { "asn": 4134, "usage_type": "DYN" },
  "risk": {
    "score": 7,
    "level": "low",
    "signals": ["dialup_pool", "hijacked_proxy", "proxy"]
  }
}
Enter fullscreen mode Exit fullscreen mode

usage_type: DYN is residential broadband — the opposite of a datacenter blocklist target — yet the risk side shows proxy / dialup_pool / hijacked_proxy with evidence_state: active. That is why network-type bans miss most of the problem: rotating residential supply lives on home and mobile ranges.

Note hijacked_proxy: the address holder is often a victim (malware turning a home router into exit capacity). Treat it as a reason for step-up checks, not an automatic account ban. Score here is low (7 / low) because evidence strength and freshness decay; active still means "act on the signal type," not "ignore because the number is small."

degraded: true appeared on this capture — some upstreams were unavailable. Official guidance: discount a degraded answer; do not pretend it is a full picture.

A policy order that respects the schema

IP99's documented read order is boring on purpose:

  1. evidence_state — active (fresh enough to score), stale (seen before, window expired, score 0, weak feature only), none (never seen; coverage gap ≠ safe).
  2. risk.score / risk.level — 0 = none, 1–29 low, 30–69 medium, 70–100 high.
  3. risk.signals — branch by type: proxy-class vs crawler vs network attributes.
  4. Ban scope — on Pulse, share_tier (T0–T3) decides whether an IP ban is one tenant or a building; the free endpoint does not expose share tier.
  5. degraded — if present, widen uncertainty.

Concrete anti-patterns:

  • Ban every hosting or every MOB / mobile hit.
  • Treat score 0 as a clean bill of health without reading evidence_state.
  • Cache yesterday's label across users or sessions (store computed_at + evidence_state, not a permanent "bad IP" tag).
  • Equate usage_type: IDC with fraud; CI, VPN, and partners live there.

A small branch that matches the schema:

if "hosting" in signals or "mobile" in signals:
    record network_context  # do not block on this alone
if evidence_state == "active" and signals ∩ {proxy, vpn, dialup_pool, cloud_phone, ...}:
    step_up_or_limit()      # captcha / throttle / review — not "ban the building" by default
if evidence_state in ("stale", "none") and score == 0:
    do_not_mark_clean()
Enter fullscreen mode Exit fullscreen mode

Try it without a key

Anonymous quota today (GET /v1/me): 500 lookups/day per client IP, 60/min, reset at midnight Asia/Shanghai. Responses also carry X-Daily-Limit, X-Daily-Remaining, and X-Daily-Reset. CORS is open (Access-Control-Allow-Origin: *), so a browser can call the endpoint directly; the quota still counts against the visitor's egress IP.

curl https://ip99.com/v1/ip/8.8.8.8
curl https://ip99.com/v1/me
Enter fullscreen mode Exit fullscreen mode

Same score shape is available as an MCP tool (ip_risk_lookup at https://ip99.com/mcp) and via the published OpenAPI document at https://ip99.com/openapi.json. Paid volume plans change quotas, not the free answer. Per-evidence rows, share_tier, and ?at= history sit on Pulse (professional).

Takeaway

hosting and mobile describe where an address sits. proxy, vpn, dialup_pool, and friends describe what it has been observed doing, with a clock. Block on the second class when evidence_state says the clock still matters; use the first class for routing and expectations. For field definitions and the free lookup, start at ip99.com.

Top comments (0)