Skip to contentSkip navigation

BGP Hijack & Routing-Hygiene Audit

Routing security you can act on. This grades a network on the conflicts and gaps that make route hijacking possible, then traces any conflict to the specific domains and organisations exposed on the affected blocks. An adversarial audit — not just a profile — for finding where a hijack could hurt and who it would hit.

The alert

A routing advisory names a prefix inside AS13335, and the hygiene scorecard for that network comes back total_prefixes 50 · prefixes_with_conflicts 0 · prefixes_with_roa 0. Zero conflicts reads as clean and zero ROAs reads as a network running no RPKI at all — one of those is true and the other is the opposite of true.

The question

Do I sign this network off as hijack-resistant, and what would tell me I am wrong?

Not "how many conflicts does it have". The conflict count is one column of the answer, and on this network it is the column that is correct and uninformative while the column beside it is simply false.

What this cannot answer

  • The rest of the network. The scorecard grades fifty announced prefixes. AS13335 announces 5,258, and all five of its RPKI-invalid announcements sit outside that fifty — the audit's only actionable rows are the ones the grade never reaches.
  • Whether a competing origin is hostile. CONFLICTS_WITH holds a prefix's whole origin set, the announcing ASN included: all 7,174 prefixes carrying the edge list their own origin among the conflicts. No step returns the conflicting ASN's orgName either, so the organisation behind a conflict is not in the output.
  • Whether a hijack ever happened. These are current-state routing rows. Origin over time is whisper.history(), a separate call.
  • A coverage-qualified verdict. whisper.assess(["AS13335"]) returns label: unknown, band: UNKNOWN, coverage: no-data. Read Coverage before reading that as reassurance.
  • Which ROAs are decaying. Every one of the 4,984 ROAs authorizing this ASN expires within six days. That is the registries' reissue cadence rather than rot, so sorting by expiry ranks nothing.

What do we know

No step here calls explain() or whisper.assess, so there is no score to lean on and none to argue with. Asked directly, whisper.assess answers no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. for the ASN: a populated row stating the absence, which is what a real absence looks like.

What is known is routing state. AS13335 announces 5,258 prefixes, isMoas is true on none of them, and no CONFLICTS_WITH edge leaves any of them. That zero is checked against the plane rather than trusted — the graph holds 7,273 MOAS prefixes and 14,942 CONFLICTS_WITH edges, so the edge type is live and the zero is a fact about this network. Zero rows is never a verdict until the plane has been asked whether it is empty.

Why

  1. 01Announced prefixes & conflicts. A CONFLICTS_WITH origin is a MOAS conflict — the hijack signal.
  2. 02RPKI coverage. An uncovered prefix can be hijacked without RPKI-invalid rejection.
  3. 03Exposed hostnames. The blast radius — which domains are exposed if a prefix is hijacked.
  4. 04Routing-hygiene scorecard. One headline row grading the ASN: how many announced prefixes it has, how many are in MOAS conflict, and how many carry an ROA.
  5. 05ROA inventory (expiry & looseness). The ground-truth ROA set authorizing this ASN, each with days until it expires and how loose its maxLength is — the authoritative RPKI picture the anchor's name-match coverage check misses.
  6. 06Imminently expiring ROAs (90 days). ROAs lapsing within 90 days — when they expire, RPKI-valid routes silently become RPKI-unknown, so these are the top remediation priority.
  7. 07Over-permissive maxLength ROAs. ROAs whose maxLength sits far above the prefix length leave room for forged more-specific sub-prefix hijacks while still reading as valid — a gap coverage checks never catch.
  8. 08ROAs by RIR trust anchor. Buckets the ASN's ROAs by issuing RIR with the soonest expiry in each, so remediation can be routed to the right registry portal.
  9. 09MOAS conflicts for a prefix input. When the indicator is a prefix rather than an ASN, this lists the competing origin ASNs announcing it — a direct hijack signal.

The pivot the score did not suggest

Every prefix in the window reads uncovered, 1.1.1.0/24 among them — and 1.1.1.0/24 has a plainly visible ROA (apnic anchor, maxLength 24, authorizing AS13335). The coverage question never needed that join. RPKI validation state is already a property of the ANNOUNCED_PREFIX the traversal is standing on.

Read it there and the same fifty prefixes return 20 valid and 30 not-found, in 1 ms against the step's 1,152. Read it across all 5,258 and the audit finally has a finding: 5,116 valid, 137 not-found, 5 invalid. Three of the five are announced more specifically than their own ROA's maxLength permits; two carry roaAsn: 0, meaning no ROA authorizes any origin for that space. 103.21.244.0/24 is the second kind — single-origin AS13335, 27 addresses, 327 hostnames on them including levebank.com.br and levecrypto.com.br. That is the blast radius this workflow exists to produce, on a row it never reaches.

Falsify it

Re-ask the coverage question in the staged form: collect the window's prefix names, UNWIND them, anchor MATCH (p:PREFIX {name: n}), then OPTIONAL MATCH the ROA onto it. That returns 14 covered of 50 in 21 ms where the composed form returned 0 in 1,152 ms.

Three forms, three answers — 0, 14, 20 — and the six prefixes between 14 and 20 explain the page. 43.230.112.0/24 is one of them: a ROA node exists with prefix 43.230.112.0/24, maxLength 24, apnic anchor, reachable from the ASN by ROA_AUTHORIZES_ORIGIN, and carrying no ROA_AUTHORIZES_PREFIX edge at all.

So count the inventory both ways. Through ROA_AUTHORIZES_ORIGIN alone, 4,984 ROAs. Adding the prefix join, 3,765. 1,219 ROAs — a quarter of this network's RPKI — have no prefix edge to join through, and every ROA step joins through it. Read r.prefix instead and over-permissive maxLength goes from 17 to 135, its IPv4 half from 2 to 8: 104.28.0.0/16 authorized down to maxLength 24, 185.54.80.0/22 down to 32. The anchored forms are on BGP & routing.

The conclusion

AS13335 is clean on multi-origin conflict and not clean on RPKI, and the scorecard says the reverse of both. Nothing it announces is in MOAS conflict, across all 5,258 prefixes rather than across fifty. Five announcements are RPKI-invalid, and 1,219 of its 4,984 ROAs are invisible to every step that reports on them. Grade the network from ap.rpkiStatus over the full prefix set, not from the scorecard row.

Four things would overturn that, each a query rather than an opinion:

  • a CONFLICTS_WITH edge appearing on any AS13335 prefix — the registry record notes MOAS data stays sparse until the next route-collector refresh, so re-run before quoting the zero;
  • ROA_AUTHORIZES_PREFIX edges backfilling, which would close the 4,984-against-3,765 gap and make the ROA steps truthful without a line of their Cypher changing;
  • ap.rpkiStatus disagreeing with an external RPKI validator on the five invalid rows;
  • any of the five invalid prefixes turning out to have a second origin, which is where this stops being hygiene and starts being an incident.

What this cost

9 named steps across the BGP, RPKI, DNS layers. The runner reports what each step returned, row by row, so the evidence and what it took to get it arrive together rather than as one number at the end.

How it uses the graph

Traverses the BGP, RPKI, DNS layers of the graph, in 9 steps:

How it walks the graph9 steps
01Announced prefixes & conflicts

Reading the ASN's announced prefixes and any competing origins…

BGPRPKIDNS
02RPKI coverage

Checking RPKI ROA coverage per prefix…

BGPRPKIDNS
03Exposed hostnames

Mapping the hostnames sitting on those prefixes…

BGPRPKIDNS
04Routing-hygiene scorecard

Routing-hygiene scorecard…

BGPRPKIDNS
05ROA inventory (expiry & looseness)

ROA inventory (expiry & looseness)…

BGPRPKIDNS
06Imminently expiring ROAs (90 days)

Imminently expiring ROAs (90 days)…

BGPRPKIDNS
07Over-permissive maxLength ROAs

Over-permissive maxLength ROAs…

BGPRPKIDNS
08ROAs by RIR trust anchor

ROAs by RIR trust anchor…

BGPRPKIDNS
09MOAS conflicts for a prefix input

MOAS conflicts for a prefix input…

BGPRPKIDNS

Key concepts