Whisper · Docs
Telecom

The NF-impersonation cure

The 5G core is a flat, all-IP HTTP/2 microservice mesh. OAuth2 authorization to the registry every function trusts, the NRF, is optional by spec (TS 33.501 §13). So reachability becomes authorization: any NF that can reach the NRF can pull any other NF's profile and speak as it, or deregister a live NF for a clean, stealthy DoS.

Whisper closes it by making the address be the NF: a routable IPv6 /128 derived from the key already behind the NF's urn:uuid:<nfInstanceId> certificate, DNSSEC-anchored and DANE-pinned, that no peer can forge and one call can revoke worldwide. A stolen token with no NF key behind it authenticates to nothing. This page walks the root cause, the reframe, the exact live calls (keyless to verify, one keyed call to provision), the attribution companion, and where it honestly does and does not bite. It is additive: it never replaces the mutual TLS and OAuth2/NRF the SBA already mandates.

Reachability is authorization

It is not a breach. The Service-Based Architecture is used exactly as it was designed: a web of microservices whose trust in one another was asserted, never proven, and weaponized by a party who was never authenticated.

Every NF (AMF, SMF, UPF, PCF, UDM, AUSF, NSSF) is an HTTP/2 + JSON service on the SBI. Each registers an NFProfile with the NRF (TS 29.510) and discovers its peers there. The SBA inherits the whole web/API threat model, and its most valuable object sits, by the spec's own allowance, effectively open: token-based authorization for the NF↔NRF exchange is not required (TS 33.501 §13.3.1.3). Where an operator leaves it off, or a token is over-scoped, reaching the NRF is the same as being allowed to use it.

The root cause has a name in the API world: BOLA (Broken Object-Level Authorization, OWASP API1:2023). The credential authenticates a claim ("I am an authorized caller") but never proves which function is on the other end. So a leaked JWS access token is indistinguishable from the real one, and the source IP that might have narrowed it down is disposable. Inside the SBA the object is the NFProfile; the same shape reappears on the northbound edge as CAMARA / Open Gateway APIs.

From a reachable NRF the moves are ordinary: read any NF's profile and impersonate it; register a rogue profile; or deregister a live NF's profile: a stealthy denial of service that leaves the target simply undiscoverable. None of it is caught by identity, because an NF's identity is a private-PKI TLS certificate no counterparty can independently verify. TS 33.310 §6.1.3c binds nfInstanceId ↔ key ↔ endpoint in that certificate's subjectAltName (a URI-ID, urn:uuid:<nfInstanceId>), a genuinely good key-derived name, but it is signed by the operator's private CA only. No roaming partner, no IPX, no regulator, and no other operator can chain it to a public anchor without bilateral cross-certification. And the DNS layer that NF discovery rides on isn't signed at all: spoof it and you redirect an NF to a rogue NRF or a forged token-issuer URL.

Two properties make the abuse invisible at the network layer. A legitimate NF is one endpoint to the functions it serves; the impersonator is one credential to a whole mesh it doesn't own. And the egress hops across clouds, an IPX, or a residential-proxy swarm, so a core SOC correlates a fresh, meaningless last IP and nothing else. The endgame is not the intrusion. It is unattributed persistence: an action bound to no verifiable, revocable identity, with no cross-operator proof of who and no fast federated kill-switch, only slow manual de-peering. Nation-state-class interconnect campaigns have stayed unattributed and un-evicted for years on exactly this vacuum. We cite that only class-level, as proof the problem is real and unsolved, never as something an identity layer alone would have stopped.

The reframe: the address is the NF

Detection will always be a step behind a credential that is genuinely valid. You can tune signaling firewalls and anomaly models forever and the impersonator still looks exactly like a peer: to your core, it is one. The strictly-stronger move is to change what the SBI trusts.

Whisper has one primitive: the address is the identity. A routable IPv6 /128 out of 2a04:2a01::/32 (announced by AS219419), deterministically derived from a key, DNSSEC-signed to the IANA root, DANE-EE pinned (3 1 1), and RDAP-registered, re-derivable and verifiable by anyone with dig.

Point it at the NF. Whisper derives each function's /128 from the key it already holds: the public SubjectPublicKeyInfo of the mTLS key behind the urn:uuid:<nfInstanceId> SAN in its SBA certificate, with the nfInstanceId as the domain separator (you pass it as device_id). The private key never leaves the NF; only its public SPKI is an input, and the /128 is a one-way function of that public half and the UUID. The derivation is deterministic and tenant-bound: the same NF key and nfInstanceId always yield the same /128, and the same vendor NF under two operators yields two unrelated /128s that no outsider can link. The SBI can then authorize on the NF's pinned identity, not a stealable token: a request either proves it is the function it claims to be, before a single detection rule runs, or it has no authority at all.

NF mTLS key urn:uuid · SBA cert SAN never leaves the NF public SPKI only public key + nfInstanceId /128 2a04:2a01:3f::a1 into NFProfile ipv6Addresses DNSSEC + DANE-EE A name any peer can verify whisper verify --trustless our API not in the trust path op:revoke → gone worldwide at DNS-TTL
The nfInstanceId UUID is already bound to the NF's key in its SBA cert: a good key-derived name trapped in a private, cross-operator-unverifiable root. Whisper binds it to a routable, publicly verifiable /128 and gives it the cross-operator revoke private CRLs and OCSP never had. Same UUID, same address field, same cert, anchored in the public DNSSEC root.

The nfInstanceId is the public index; the /128 is its cryptographic counterpart. The nfInstanceId is a structured UUID flowing through every NRF registration and discovery; useful for interoperability, but not a secret. The /128 derives from the in-NF key salted by that UUID, so the UUID alone yields nothing. You cannot go nfInstanceId/128 without the key, there is no enumerable directory, and RDAP / reverse DNS return the registry object, never the NF's whereabouts.

What changes

Nothing here is a new detection rule. Each row is an abuse technique that stops being possible, not one you catch after the fact.

The abuse today Why it dies under identity
Reach the NRF → become any NF Reachability is no longer authorization. A peer that reaches the NRF still cannot present an NF identity whose key it doesn't hold; every forgery is a DNSSEC / DANE inconsistency any counterparty catches with stock tools: dig -x names an identity whose AAAA and TLSA don't agree.
Rotate egress across clouds / IPX / proxies Identity is not the source IP. The last IP was never the credential, so rotating it across AWS, GCP, Azure, an IPX hub, or a residential swarm changes nothing about whether the caller can prove the NF.
Replay a stolen JWS token / over-scoped grant The bearer has no NF key behind it. A state-changing call terminates mutually-authenticated to the target NF's /128 (whose DANE pin any counterparty checks against the public root), so a valid-looking token that can't prove the nfInstanceId never had authority. BOLA loses its leverage: reaching the NRF no longer reaches any NF.
Deregister a live NF (stealth DoS) A deregister request that can't prove the target NF's identity is just noise. The verifiable, DNSSEC-anchored name and its DANE pin exist independently of the NRF record an attacker would try to pull.
Blast radius on compromise One revoke tears down the /128, its PTR, and its DANE pin worldwide at DNS-TTL speed, across operator boundaries. No per-operator CRL you hope every peer fetched, no bilateral PKI exchange. Compromise one NF and you have compromised that NF, not the mesh.

Provision an NF identity

Shipped & live. Deriving an NF /128 from the key it already holds, with its nfInstanceId passed as device_id, is in production today. Provision one with the control-plane call below and verify it from the DNSSEC root with tools already on your machine.

Provisioning is one control-plane call to POST https://graph.whisper.security/api/query with your X-API-Key header. You pass the NF's public key material (the base64 SubjectPublicKeyInfo of the mTLS key behind its SBA cert) and its nfInstanceId as device_id; you get back the deterministic /128 (drop it into the NFProfile's ipv6Addresses) and a WireGuard config to source the NF's traffic from that address.

The call

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

Over stock tools: a heredoc keeps the single-quoted Cypher literals intact, so this runs as-is:

# the public key only: the private key never leaves the NF's HSM / secure store
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

The response

# result carries the deterministic identity plus a ready-to-apply tunnel
address        2a04:2a01:3f::a1
fqdn           003f0000000000a1.<tenant>.agents.whisper.online
ptr            003f0000000000a1.<tenant>.agents.whisper.online
state          active                       # DNSSEC + DANE-EE (3 1 1) live at provision time
wireguard_config   [Interface] …            # source the NF's egress from its own /128

The NF now has a name any peer can prove and an address it egresses from. Reverse DNS resolves the /128 to that identity, a TLSA record pins the leaf key (the same key already behind the NF's urn:uuid cert), and RDAP registers the object under 2a04:2a01::/32. The full seven-proof chain, published atomically with the allocation, and it needs no NRF API change and no new CA.

Idempotency and errors

The call is deterministic and honest about conflicts: conservative in what it emits, liberal in what it accepts. It answers a bad body with ProblemDetails, exactly as the NRF's own OpenAPI would.

You send You get
The same NF key + nfInstanceId again The same /128: idempotent, safe to retry, safe to run on every NF start-up. No duplicate identities, no churn in the NFProfile.
The same NF key with a different nfInstanceId on your tenant 409 Conflict: a key binds to exactly one nfInstanceId. The error.detail tells you which UUID it is already bound to.
A non-string device_id (a number, an array, null) 400 with an actionable detail, never an opaque 500. Send the nfInstanceId as a string.
i

Shipped vs roadmap. The generic device_id domain separator is live: pass your nfInstanceId there today. A first-class typed --nf-instance-id CLI/API argument is on the roadmap; provision through the control-plane call above, which runs as-is. On the CLI, whisper create --register mints a generic identity and whisper verify / whisper policy / whisper logs / whisper kill --revoke drive the rest.

Revoke, worldwide

A scale-in, a software upgrade that re-keys, a decommission, a changed roaming partner, or a compromised NF is one call. It's provable with the same stock tools that proved the identity existed, no Whisper software required.

# the control-plane op…
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:3f::a1'}})
# …or the CLI
whisper kill --revoke 2a04:2a01:3f::a1

# now prove it, worldwide, at DNS-TTL speed, across operator boundaries:
dig -x 2a04:2a01:3f::a1 +short                       # -> nothing
curl -s https://whisper.online/verify-identity/2a04:2a01:3f::a1
# -> {"is_whisper_agent": false, ...}

This kills the /128 and its egress authorization faster than any CRL or OCSP could propagate: the federated kill-switch private PKIs never had. It does not revoke the operator's TLS certificate; that stays your CA's job. Sell it as an additional, faster kill-switch, not a replacement.

Verify it: keyless, no account

The identity is public by design, so anyone (a roaming partner, an IPX, a regulator, your PSIRT, another operator) can check an NF without your key and without taking Whisper's word for it. This is the keyless half of the two-tier surface: verify with no key, provision and govern with your key.

# no key, no account: re-derive and verify the NF's identity, trustless to the IANA root
whisper verify --trustless 2a04:2a01:3f::a1

# or with only curl: the keyless full-chain verdict
curl -s https://whisper.online/verify-identity/2a04:2a01:3f::a1
# { "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:3f::a1 +short
# 003f0000000000a1.<tenant>.agents.whisper.online.

# the registry object for the /128: RDAP, typed JSON
curl -s https://whisper.online/ip/2a04:2a01:3f::a1 | jq '.handle, .parentHandle'
# "2A04:2A01:3F::A1/128"
# "2A04:2A01::/32"

The --trustless flag is the point: nothing there calls back to Whisper's own API as an authority. The CLI re-derives the DNSSEC chain to the IANA root, on your machine, with your resolver. This is what a private NRF and an operator-private CA cannot give you: a home operator verifies a visiting peer against the public root, not the IPX's word.

same peer, two ways to believe it Home operator the verifier · SEPP / N32-c HPMN IPX hub · N32-f / PRINS semi-trusted: reads & rewrites whitelisted JSON; trust asserted Public DNSSEC root · IANA DANE-EE 3 1 1 · the shared anchor no private CA, no IPX in the path Visiting peer NF urn:uuid cert (peer CA) /128 + DANE pin old way: trust the chain ✗ resolve /128 · pull DANE pin verify at the IANA root ✓
At the roaming border, mutual TLS proves the peer only inside its own operator's private CA. Whisper lets the home operator verify the same identity (the urn:uuid key, now a DANE-pinned /128) against the public DNSSEC root, independent of the IPX's assertion and without cross-certifying a single CA. It hardens the N32-c spoofing vector GSMA FS.36 names; it complements PRINS and the SEPP, it does not replace them.

Govern, observe, attest

An identity you can prove is also one you can watch and fence. Because every NF's name resolves through Whisper's own authoritative DNS and RDAP, the owner sees exactly who looked, governs precisely what each function may reach, and gets a non-repudiable record of every mint and revoke. All of the following are shipped control-plane ops on the same keyed endpoint.

# default-deny egress: an AMF may reach the NRF and SCP, nothing else
whisper policy set --default deny \
  --allow nrf.5gc.example-mno.net,scp.5gc.example-mno.net

# op:firewall: allow/deny by ip, cidr, host, or port; op:budget caps and kills
CALL whisper.agents({op:'firewall', args:{agent:'2a04:2a01:3f::a1',
  deny:['0.0.0.0/0'], allow:['nrf.5gc.example-mno.net:443']}})
CALL whisper.agents({op:'budget',   args:{agent:'2a04:2a01:3f::a1', cap:'5GB/day'}})

# op:lookups: WHO resolved or RDAP-queried this NF's identity (a recon tripwire)
curl -s https://whisper.online/ip/2a04:2a01:3f::a1/lookups
# PTR / AAAA / TLSA + RDAP accesses against this NF's records:
# catch a peer enumerating your NFs IN RECON, not in the post-mortem

The same address-is-identity primitive that governs a compromised NF also governs the AI agents your NOC, your OSS/BSS automation, and your CAMARA developer edge are about to run: per-agent /128, per-agent logs, default-deny egress, one revoke. From day one.

Name what already got in

Identity stops the next impersonation. It does not name the operator behind the sessions already in your logs. Interconnect abuse is unattributed by design, so the same platform back-traces them, and the attribution survives the rotation because it fingerprints the operator's infrastructure and tooling, not the ephemeral egress IP.

Take a suspect egress IP straight from your core SOC logs and ask the graph who really operates it. This runs read-only over the same public graph API, with your key:

# who really operates a host, even behind a CDN, an IPX, or a cloud front
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(\"34.90.x.x\")"}'
# operator fingerprinted across AWS / GCP / Azure; residential swarm collapsed by JA4

The read-only verbs (identify, origins, walk, variants, history) run over that one endpoint against a live internet-infrastructure graph of fused BGP, DNS, WHOIS, TLS, hosting, and threat intelligence. Cloud and IPX rotation collapses through origins and walk, which cluster shared ASN, hosting, and certificate lineage into one infrastructure genealogy; where a subscriber IP gives an infra graph nothing to grab, a JA4/JA3 client fingerprint travels with the tooling and collapses a residential-proxy swarm to one operator. You can also express interconnect abuse directly as read-only Cypher (a question rather than a signature), such as "one source touching N distinct NF identities in a window":

# schema illustrative: the interconnect question, not a stored signature
MATCH (src)-[t:TOUCHED]->(n:NfIdentity)
WHERE t.window = "15m"
WITH src, count(DISTINCT n) AS nfs
WHERE nfs > 50
RETURN src, nfs ORDER BY nfs DESC
# -> 1 source → 2,187 distinct NF identities / 15m; egress collapsed to one operator

Every answer is reproducible, replayable JSON: the cryptographic paper trail NIS2 Art.23's 24-hour / 72-hour / one-month reporting clock needs, not a screenshot.

These graph verbs are the API surface: you call the endpoint directly, as above. There is no whisper identify / graph CLI subcommand; the CLI covers the control plane (create, verify, policy, logs, kill), and the graph is the query API. See Graph & cognition.

Where it fits: standards, SIEM, integrations

Whisper is additive. It rides on top of the anchors 3GPP mandates and the SIEM you already run; it replaces none of them. It never inspects an SS7, Diameter, or GTP message, never touches the 5G-AKA / UICC subscriber plane or the air interface. It anchors the IP / DNS / transport boundary, strongest at the trust boundaries where independent verification matters most: NF discovery and its DNS, the N32 roaming border, NEF / CAMARA exposure, and management.

Compliance. The strongest, least-contestable claim: DNSSEC + DANE close the DNS-spoofing / rogue-NRF / forged-issuer gap that TS 33.501's mandated mTLS + OAuth2 leave open on the name layer. Beyond that: cryptographic attribution accelerates the who/where forensics NIS2 Art.21(2)(b) / Art.23 demand; a per-NF /128 micro-perimeter is the NSA/CISA ESF 5G Cloud anti-lateral-movement control and advances CISA ZTMM's Identity + Visibility pillars; a DANE-pinned NF resolution is an EU 5G Toolbox TM02 move; a DANE-pinned peer identity hardens the N32-c vector GSMA FS.36 names; and a per-component /128 serves O-RAN WG11's Zero-Trust Architecture Identity pillar across a multi-vendor RAN. The full mapping lives in NESAS · NIS2 · 5G Toolbox.

i

Honest caveats: say them out loud. Whisper never replaces 3GPP mTLS + OAuth2/NRF (mandatory and primary; this is a second, independent, DNS-anchored layer). It is not a NESAS / SCAS certification control and not a CRA conformity route: a differentiator and PSIRT tool, not a shortcut through certification. It does nothing for FCC rip-and-replace. And its revoke kills the /128 and the egress authorization faster than any CRL/OCSP, but revoking the operator's TLS cert stays the operator CA's job.

SIEM: shipped vs roadmap. The Splunk, Microsoft Sentinel and OpenCTI connectors ship today; findings arrive as signed JSON mapped to CEF and ECS fields. On the roadmap, labelled as such: STIX 2.1 over TAXII export, and a per-sector machine-readable export for peer sharing.

Integrations (proposed, not vendor-endorsed). Whisper anchors the cloud, IP, and DNS boundary, never the SS7/Diameter/GTP message, the SEPP's in-line PRINS transform, or the air interface:

And it is built to fail open: a Whisper outage never drops a call. Checks degrade to the anchors you already run, and connectivity is preserved. Anycast on AS219419, no single node in the path.

Next