Whisper · Docs
Telecom

Telecom

A reachable NRF shouldn't be able to impersonate any network function in the core.

Inside the 5G service-based architecture, one function authenticates another with mutual TLS at the handshake. But the identity it proves is a certificate signed by an operator-private CA, verifiable only to that operator, and the authorization step above it is optional by spec. Whisper closes the gap with one primitive: the network function's address is its identity, bound to the nfInstanceId the NF already carries in its certificate SAN, DNSSEC/DANE-anchored, and publicly verifiable across operators. This page is the telecom front door to the Whisper docs. The full technical library (DNSSEC, DANE, RDAP, the control-plane API) sits one click down the sidebar, shared verbatim with whisper.online/docs.

The problem: reachability ≈ authorization

The 5G core is a flat, all-IP mesh of HTTP/2 + JSON microservices: AMF, SMF, UPF, PCF, UDM, AUSF, each registering a NFProfile with the NRF and discovering peers through it (3GPP TS 29.510). Mutual TLS on the service-based interface is mandatory; OAuth2 token-based authorization between an NF and the NRF is not. TS 33.501 §13.3.1.3 makes it optional, and GSMA's 5G Interconnect Security group flagged this as a structural weakness. The consequence is blunt: reachability becomes authorization. Any NF that can reach the NRF can pull any other NF's profile and impersonate it, or deregister a live NF for a clean, stealthy denial of service. The mesh inherits the entire web-and-API threat model: broken object-level authorization (OWASP BOLA), over-scoped tokens, exposed SBIs, all one microservice hop from the subscriber plane.

And the identity that does exist doesn't travel. Every NF certificate chains to a private, per-operator root, so no roaming partner, IPX carrier, regulator, or other operator can independently confirm "this really is operator X's AMF." Trust is asserted, never provable. The modern stack is weakest at the N32 roaming interface between two SEPPs, mediated by semi-trusted IPX hubs, and at the legacy SS7 / Diameter / GTP interconnect, which trusts by default and lives on indefinitely for backward compatibility. That unverifiable identity is exactly the seam an attacker works.

One reachable NRF → every NF: every egress is disposable Any SBI client reach ≈ authorization OAuth2 optional · §13 in-mesh NRF 5G discovery · TS 29.510 hands out every NFProfile claim ✓ · machine ✗ enumerate NFProfiles: the whole core impersonate · deregister (stealth DoS) · N32 spoof · IRSF …reached in through disposable egress: IPX hub cloud VM grey route residential swarm SOC logs a meaningless last IP
The whole kill chain leans on one spec footnote: OAuth2 authorization at the NRF is optional (TS 33.501 §13), so reachability becomes authorization. The egress is disposable too, so the last IP the SOC records was never the attacker.

The bill is not theoretical. The CFCA puts global telecom fraud at $38.95B in 2023, roughly 2.5% of revenue. $6.23B a year of that is International Revenue Share Fraud, a category that rides entirely on interconnect trust. The roaming fix built to harden this, the SEPP, is barely deployed: industry analysis reports ~70% of operators lack the cloud-native capability a SEPP needs. Independent pentesting has found the legacy planes wide open: one vendor assessment reported every one of 28 tested operator networks vulnerable to GTP-based impersonation, fraud, or denial of service (Positive Technologies, ~2020, vendor pentest, dated). Detection will always trail a credential or a signaling peer that is genuinely trusted. The strictly-stronger move is to change what the counterparty trusts.

The cure: the address is the NF

Shipped & live. Deriving an NF /128 from the network function's own SBA key + the nfInstanceId it already carries is in production today. Provision one with the control-plane call below and verify it from the DNSSEC root, across operators, with tools already on your machine.

Whisper gives each network function (AMF, SMF, UPF, PCF, a SEPP, an O-RAN component) a routable IPv6 /128 out of 2a04:2a01::/32 (announced by AS219419), derived deterministically from the NF's public key: its SubjectPublicKeyInfo, the public half of the SBA certificate the NF already presents on mutual TLS, with the nfInstanceId as the domain separator. That UUID is not incidental. TS 33.310 §6.1.3c mandates the SBA certificate carry a subjectAltName URI-ID of urn:uuid:<nfInstanceId>, so the key ↔ instance-id ↔ endpoint binding already exists, just sealed inside the operator's private CA. The private key never leaves the NF; only its public SPKI is an input. The result is DNSSEC-anchored, DANE-EE 3 1 1 pinned to that same certificate, and RDAP-registered: re-derivable and verifiable by anyone with dig.

the address is the NF NF key + nfInstanceId SBA cert · urn:uuid SAN ECDSA · CMPv2-enrolled private key stays on the NF public SPKI + nfInstanceId /128 2a04:2a01:5e0::a3f → NFProfile.ipv6Addresses DNSSEC · DANE 3 1 1 · RDAP Any operator verifies it whisper verify --trustless no cross-cert · no NRF access op:revoke → gone worldwide at DNS-TTL
The nfInstanceId is already a URI-ID in the NF's certificate SAN (TS 33.310), an identity trapped in a private, per-operator CA. Whisper binds the same UUID, from the NF's own key, to a routable, publicly verifiable /128 that drops straight into NFProfile.ipv6Addresses, and gives it the cross-operator off-switch the private root never had.

Because the derivation is tenant-bound, the same NF key under two operators yields two unrelated /128s: an outsider cannot link a function across networks, which sits naturally alongside the topology hiding a SEPP already performs. Because the domain separator is the nfInstanceId, the instance-id alone yields nothing: it flows through every discovery response and is not a secret, yet you cannot go nfInstanceId/128 without the key, there is no enumerable directory, and RDAP and reverse-DNS return the registry object, never the NF's operational whereabouts.

What becomes true the moment an NF holds one:

Additive, never a replacement. Whisper complements the controls 3GPP already mandates: mutual TLS on the SBI, OAuth2 authorization with the NRF as authorization server, the operator-private CA and CMPv2 enrolment, SEPP N32-c/N32-f and PRINS topology hiding, O-RAN WG11's mTLS + CMPv2. It is the publicly verifiable, DNSSEC/DANE-anchored layer on top, anchoring the trust boundaries where independent verification actually matters: NF discovery and the DNS beneath it, the N32 roaming border, NEF/CAMARA exposure, and management, all at the IP, DNS, and transport layer. You can even DANE-pin your existing SBA endpoint's certificate to DNSSEC and cut single-CA mis-issuance risk out-of-band. Whisper never reaches into the mTLS session on the SBI itself, the 5G-AKA / SUCI subscriber plane, or the O-RAN fronthaul; it keeps the nfInstanceId's existing cert binding and adds the two things a private root lacks: public cross-operator verifiability and DNS-TTL revocation, with no NRF OpenAPI change and no re-key.

Nothing is issued in the dark: every mint and every revoke lands in a public, append-only Merkle transparency log, Ed25519-signed and anchored to Bitcoin via OpenTimestamps, that you, a peer operator, and a regulator can audit. (Honest status: tamper-evident and Bitcoin-anchored today; independent third-party witnessing is the next step, and the log already speaks the witness protocol.)

Provision an NF identity

Provisioning is one control-plane call over the public API: POST https://graph.whisper.security/api/query with your X-API-Key. Hand it the NF's base64 SPKI and its nfInstanceId; it returns the deterministic /128 and a WireGuard config for source-bound egress:

CALL whisper.agents({op:'connect', args:{
  tier:'wireguard',
  identity_public_key:'<base64 SPKI of the NF's SBA key>',
  device_id:'3f2504e0-4f89-11d3-9a0c-0305e82c3301'   // the nfInstanceId (urn:uuid in the cert SAN)
}}) YIELD op, ok, status, result, error
RETURN op, ok, status, result, error

Send it with your key. The heredoc keeps the single-quoted Cypher literals intact, so this runs as-is:

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H 'content-type: application/json' \
  --data @- <<'JSON'
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard', identity_public_key:'<base64 SPKI>', device_id:'3f2504e0-4f89-11d3-9a0c-0305e82c3301'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}
JSON
# response
{ "op": "connect", "ok": true, "status": "created",
  "result": {
    "address": "2a04:2a01:5e0::a3f",
    "fqdn":    "nf-3f2504e0.amf.<tenant>.agents.whisper.online",
    "wireguard": { /* peer, keys, allowed-ips */ }
  } }

The call is idempotent and liberal in what it accepts, strict in what it returns: re-running with the same key and nfInstanceId returns the same /128; a different instance-id for a key already registered on your tenant is a clear 409, not a silent overwrite; a non-string device_id is a 400 that tells you exactly what was wrong, not an opaque 500. That's the same Postel discipline the NRF itself shows when it answers bad JSON with a ProblemDetails object instead of a stack trace. The device_id argument is generic: pass the nfInstanceId, the OAuth2 client_id (which is the nfInstanceId), or a SEPP's identity, whatever native identifier the function carries.

i

The returned /128 drops straight into the NF's NFProfile.ipv6Addresses at the NRF: no OpenAPI change, no re-registration, no new key. A dedicated --nf-instance-id CLI flag is on the roadmap; today, NF provisioning is the control-plane call above (which is live). The shipped CLI verbs are whisper verify --trustless, whisper create --register, whisper kill --revoke, whisper policy, and whisper logs. See CLI & one-command.

Verify it yourself, no account needed

Every NF identity is checkable with no key and no login, from the internet's own records. That's the whole point at a trust boundary, where the party checking is a different operator. The whisper CLI does the full walk in one call:

whisper verify --trustless nf-3f2504e0.amf.<tenant>.agents.whisper.online

 DNSSEC chain valid to the IANA root
 DANE-EE (TLSA 3 1 1) leaf matches the NF's SBA certificate
 RDAP: registered under AS219419 · 2a04:2a01::/32
identity: VERIFIED, and our own API was never trusted

Or reach for the raw records directly: the same answer, from stock tools:

# the public verify endpoint: evidence chain in JSON
curl -s https://whisper.online/verify-identity/2a04:2a01:5e0::a3f | jq
{ "is_whisper_agent": true, "dane_ok": true, "jws_ok": true, "evidence": { /* … */ } }

# the address is the NF: forward-confirmed reverse DNS names it
dig -x 2a04:2a01:5e0::a3f +short
nf-3f2504e0.amf.<tenant>.agents.whisper.online.

# the registry object: who holds the address, and under which allocation
curl -s https://whisper.online/ip/2a04:2a01:5e0::a3f | jq

None of these calls Whisper as an authority. --trustless re-derives the proof against the public DNSSEC root, exactly as any resolver could. A home operator can verify a visited network's peer NF or SEPP against a public anchor instead of trusting the SEPP's assertion or an IPX hub in between. See Verify an agent for the full keyless check and DANE & TLSA for the pin, byte for byte.

Revoke worldwide and govern in between

A compromised NF, a decommissioned function, a rotated key, a de-peered interconnect partner: one call tears down the /128, its PTR, and its DANE pin everywhere at DNS-TTL speed:

CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:5e0::a3f'}})

# after the TTL: dig -x returns nothing, verify returns false
whisper kill --revoke 2a04:2a01:5e0::a3f

This is a cross-operator kill-switch that propagates at cache-TTL: no bilateral PKI exchange, no per-operator CRL you hope every peer fetched. Honest boundary: this revokes the identity, its route, and its egress authorization faster than CRL/OCSP; it does not revoke the operator's SBA TLS certificate. That stays your operator CA's job. Sell it as an additional, faster kill-switch, not a replacement for CMPv2 revocation. Revocation is the endpoint; the same control plane also governs what a live NF may reach in between. Egress is source-bound to the NF's /128, so policy is enforced by name and by address:

# default-deny: this NF may reach ONLY its NRF and its peer SEPP
whisper policy set --default deny --allow nrf.5gc.example-mno.net,sepp.5gc.example-mno.net

# per-NF firewall (allow/deny by host, cidr or port) and a traffic budget + kill-switch
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:5e0::a3f', deny:['0.0.0.0/0'], allow:['nrf.5gc.example-mno.net:443']}})
CALL whisper.agents({op:'budget',   args:{agent:'2a04:2a01:5e0::a3f', max_mb_per_day:500}})

Per-NF /128 plus egress governance is a network-layer micro-perimeter against lateral movement: the isolate-workloads posture NSA/CISA's ESF 5G Cloud guidance asks for, and the Identity and Visibility pillars of the CISA Zero-Trust Maturity Model, expressed as one call to provision and one to revoke. Because each record and telemetry stream can be bound to, and signed under, the NF's forge-proof /128, a peer operator, an interconnect partner, or your own settlement can trust the numbers came from the real function, not a spoofed feed. See Egress governance for the full policy surface.

Attribution: name whoever already reached you

Identity stops the next forgery; the graph names the operator behind the sessions already in your logs: attribution that survives IP rotation because it fingerprints the operator and the tooling, not the ephemeral egress IP behind an IPX hub, a cloud VM, or a residential proxy. Run it as read-only Cypher over the same public API with your key (there is no CLI subcommand for this; it is the graph API directly):

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H 'content-type: application/json' \
  -d '{"query":"CALL whisper.identify(\"185.x.x.x\")"}'
# operator fingerprinted across IPX / cloud / residential; egress swarm collapsed by JA4

The read-only verbs (identify, origins, walk, variants, history) each return a reproducible, replayable JSON evidence chain your core-NF SOC, your PSIRT, and a regulator can replay. Cryptographic attribution is exactly what the NIS2 incident-reporting clock needs (Art. 23: early warning within 24h, notification within 72h, final report within a month), so you can name who and where instead of shipping a meaningless last IP. More in Graph & cognition.

Lookups: see who's enumerating your core

An identity you can prove is also an identity you can watch. Because every NF's name resolves through Whisper's own authoritative DNS and RDAP, the owner can ask who looked: a reconnaissance tripwire the private, out-of-band NRF registry never gave you. op:lookups returns who resolved or RDAP-queried an NF's identity, so you see a roaming partner or a would-be peer enumerating your core before an N32 message lands, not in the post-mortem afterward:

CALL whisper.agents({op:'lookups', args:{agent:'2a04:2a01:5e0::a3f', window:'24h'}})

# the same reverse-observability view, keyless, per address
curl -s https://whisper.online/ip/2a04:2a01:5e0::a3f/lookups | jq
# → who resolved this NF's PTR/AAAA/TLSA and hit its RDAP object, and when

Paired with op:logs (the NF's own outbound activity) and /ip/<addr>/transparency (its ordered lifecycle in the Merkle log), you have both halves of the picture: what an NF reaches out to, and who is reaching in to look at it.

What ships today, and what's on the roadmap

We label these honestly so you can plan against them.

Shipped & liveOn the roadmap
NF /128 from the NF's SBA key + nfInstanceId: DNSSEC + DANE-EE + RDAP A dedicated --nf-instance-id CLI flag (provision via the control-plane call today)
Control-plane provision, verify, revoke; egress governance (policy/firewall/budget); op:lookups; the Merkle transparency log; the attribution graph over the public API STIX 2.1 over TAXII export
The Splunk, Microsoft Sentinel and OpenCTI connectors (signed, replayable JSON → CEF / ECS fields) telecom-ISAC machine-readable JSON export

The integration guides below describe proposed integrations at the SBI, roaming, and IP boundary, designed to complement the stack you already run, not endorsed by 3GPP, GSMA, or any vendor, and never named against a specific operator as a breach victim. Two honest boundaries worth stating plainly: this is not a GSMA NESAS / SCAS certification control and not an EU CRA conformity route. It is a defense-in-depth differentiator and a PSIRT attribution tool. It does nothing for FCC rip-and-replace, which is a supply-chain-provenance problem of a different class. Nation-state router and edge implants live below the identity layer; we cite those campaigns only as class-level proof that cross-operator attribution and fast eviction remain unsolved, never as something an identity layer alone would have stopped.

The five Telecom guides

The telecom story, in depth: each page is self-contained and copy-paste runnable.

The full technical library

Telecom rides on the same address-is-identity platform as every other agent on the network, so the whole shared library applies here unchanged, and every page has a clean Markdown twin at the same path + .md. Start with these; the rest is in the sidebar.