energy.whisper.online · Grid-API abuse

One stolen token shouldn't be able to dispatch a fleet it never owned.

The attacker mints a bearer against your aggregator's cloud API — or reuses one that's valid across two platforms — enumerates every LFDI behind it, and pushes legitimate-looking active-power setpoints, forced disconnects, or firmware from ordinary egress. Your IP allowlists pass it; your DERMS can't tell it from the head-end; your logs record a meaningless last IP. It works for one structural reason: your DER devices have no identity they can prove, so the token authenticates a claim, never the inverter on the other end.

We give them one. The address is the inverter — a routable, DNSSEC-anchored /128 bound to the LFDI it already carries, that no one can forge, so a command that can't prove the target DER's identity fails — and you can revoke it worldwide in a single call. Give every DER an identity it can prove — and an off-switch its own PKI never had.

whisper verify --trustless — anchored at the IANA DNS root. Our own API is not in the trust path.

~35k solar devices from 42 vendors sit exposed on the open internet
~195 GW of solar coordinated by one platform pair — a stolen OAuth/JWT token took over any account
<2% of inverters (~4.5 GW) modeled enough to force EU grid load-shedding at 49 Hz
~800 PV monitors hijacked into Mirai — the first confirmed attack on PV generation
10+/yr solar-vendor vulns for 3 years — 80% high/critical, 32% CVSS 9.8–10
0 revocation — IEEE 2030.5 device certs are life-long, no CRL, no OCSP

This is how a fleet you built gets dispatched by someone who never owned an inverter.

No zero-day required. The “many small devices, one control plane” shape means a single bearer token becomes authority over thousands of EndDevices — the aggregator head-end and its API used exactly as built, at fleet scale.

01 · RECON

Find the control plane

An internet-exposed gateway (~35k on Shodan across 42 vendors) or, higher-value, the vendor cloud / aggregator API that fronts a whole fleet of DER.

02 · TOKEN

Mint or steal the bearer

Hit an unauthenticated /oauth2/token, exploit a broken-authorization endpoint, or lift a hard-coded key. A valid OAuth/JWT bearer becomes the fleet authority — no per-device identity in the way.

03 · ENUMERATE

One token, one fleet

Iterate account and org IDs and the LFDIs of the EndDevices behind them. “Many small devices, one control plane” becomes “one token, thousands of inverters.”

04 · COMMAND

Legitimate-looking dispatch

Push active-power setpoints, forced disconnect/reconnect, coordinated on/off, or malicious firmware. The token is valid; the egress is ordinary; the DERMS sees the head-end.

05 · ROTATE

Every last IP is disposable

Hop across Amazon, Google and Azure, or a residential-proxy swarm, every few requests. Your SOC sees a fresh last IP and correlates nothing.

06 · STRESS

Swing the aggregate

Synchronize the fleet to move real power. Research models <2% of inverters as grid-relevant — and the token stays valid until one vendor rotates it.

the shape — one stolen token, one control plane, a whole fleet, real power on the grid Stolen token OAuth / JWT bearer = fleet authority 01 · 02 Aggregator head-end one control plane /oauth2/token · broken-auth 05 · egress rotates AWS·GCP·Azure + residential — last IP is a decoy thousands of EndDevices — one LFDI each EndDevice · LFDI …04e0 EndDevice · LFDI …8f21 EndDevice · LFDI …a7c3 · · · × thousands EndDevice · LFDI …e19b 03 · enumerate 04 · command coordinated setpoints · disconnect · firmware 06 · Grid stress aggregate swing <2% ≈ 4.5 GW → 49 Hz (modeled, not observed)
The kill chain is a funnel: one stolen token, through one control plane, becomes coordinated authority over a fleet of EndDevices — and the grid-stress figure is a research model, not an observed event. Every stage leans on the same missing thing: a per-device identity in the command path.

Invisible at the network layer by design: a real operator is one head-end to a fleet it owns; the abuser is one token to a fleet it doesn't — and every IP it ever shows you is disposable. This is not hypothetical. A single cloud-platform pair coordinating ~195 GW of solar could be made to mint a token for any account and take it over; a bearer valid on one platform proved reusable across another; ~800 monitoring devices were hijacked into Mirai through one unauthenticated command-injection flaw — the first publicly confirmed cyberattack on PV generation; and a longitudinal look at one vendor family's disclosures (the SUN:DOWN class) found 10+ high/critical vulns a year for three years running. All class-level — the pattern, not a name.

Stop detecting the abuse. Prove the identity.

Detection will always be a step behind a credential that is genuinely valid. You can tune models forever and the abuser still looks exactly like your aggregator — because, to your backend, it is one. The only strictly-stronger move is to change what the command path trusts.

Today · the command path trusts a bearer secret

An OAuth/JWT token, an API key, a session — whoever holds it can present it. That is the whole problem in one line: the credential proves a claim, never which DER is on the other end, so a stolen one is indistinguishable from the real head-end, and the source IP that might have narrowed it down is disposable. The root cause has a name — OWASP broken authorization / BOLA: authority is attached to a token, not to the machine it commands.

Tomorrow · the command path authorizes a DER that proves itself. Bind authority to an identity the inverter holds and can demonstrate cryptographically — not a secret anyone can copy. Now a dispatch either proves it is aimed at the DER it claims to command, or it has no authority at all — before a single anomaly rule runs. Detection stops being the last line of defense and becomes a bonus.

"A minted OAuth token or a leaked aggregator key passes every auth check — how do you catch abuse that is authenticated?"

You bind authority to the DER, not the bearer. A state-changing dispatch terminates mutually-authenticated to the target inverter's /128 — the device co-signs at the transport boundary — so a token can't reach an LFDI it can't cryptographically address. A request that passes auth but can't prove the identity never had authority in the first place, and BOLA loses its leverage: elevating to any account no longer reaches any inverter.

That identity already has a home on the network you run: an address. Here is how the DER's own key becomes an address no stolen token can forge.

Bind the command path to the LFDI the inverter already carries.

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-anchored, DANE-EE pinned, RDAP/WHOIS-registered — re-derivable and verifiable by anyone with dig. whisper verify --trustless checks it against the IANA root; our own API is not in the trust path.

Point it at the device. Derive each inverter's — or each gateway's or EVSE's — /128 from the public key behind the identifier it already carries: the IEEE 2030.5 LFDI (itself a SHA-256 of the device's X.509 cert), a SunSpec/Kyrio device cert, a secure element, or a TPM — passing the LFDI as the device_id domain separator. The private key never leaves the device; the address is a one-way function of its public half and that identifier. No re-flashing the 25M+ inverters already in the field — you bind the identity they were born with.

the dispatch checks the inverter, not the bearer DERMS head-end proves the target /128 mutual auth · DANE-EE Stolen token valid bearer, no device key = claim, not a machine Dispatch / command API authorizes on the DER's /128 DANE-EE 3 1 1 · transport boundary complements 2030.5 · never the bus identity proven ✓ can't prove /128 ✗ Setpoint applied to the real EndDevice ✓ command lands Rejected no identity behind the token ✗ authenticates to nothing op:revoke → the /128 is gone worldwide at DNS-TTL
State-changing dispatch terminates mutually-authenticated to the target DER's /128 — the inverter co-signs at the transport boundary — so a stolen token can't reach an LFDI it can't cryptographically address. One leaf key per identity; never a shared root. Whisper anchors the device↔cloud boundary and never reaches into the IEC 62351 substation bus, the DNP3 outstation, or the ISO 15118 charging handshake.

"One token → a whole fleet" becomes physically impossible

You cannot present thousands of DER identities whose keys you don't hold. Every forgery is a DNSSEC/DANE inconsistency any verifier catches.

IP rotation becomes irrelevant

Identity is not the source IP. The "last IP" was never the credential — so rotating it, across clouds or residential proxies, changes nothing.

Stolen tokens fail

A minted or reused bearer with no device key behind it authenticates to nothing. The dispatch path checks the inverter, not the bearer.

One revoke kills a compromised inverter worldwide

At DNS-TTL speed: dig -x returns nothing; verify returns false. The revocation IEEE 2030.5's life-long certs never had.

"IEEE 2030.5 already gives every inverter a certificate. Why isn't that enough?"

Because it can't be revoked and no one outside the utility can verify it. The LFDI is a SHA-256 of the device's own certificate — a genuinely good key-derived name — but it lives in a private SERCA→MCA→MICA root, is allow-listed per-utility out-of-band, isn't addressable, and “cannot be updated or revoked … CAs are not required to issue CRLs nor provide OCSP.” Whisper keeps the key-derived property and adds what it lacks: publicly verifiable, addressable, and revocable at DNS-TTL.

Attaches to what you already ship — it does not replace it. Whisper complements the anchors you already trust — the IEEE 2030.5 / SunSpec / Kyrio device certificate and its LFDI, IEC 62351 on the substation bus, OpenADR VEN/VTN, ISO 15118 Plug & Charge, TPM/HSM/secure elements. It is the publicly verifiable, DNSSEC/DANE-anchored layer on top, anchoring the device↔cloud boundary: no bespoke CA trust store to push to every inverter, and revocation at DNS-TTL speed instead of a certificate that can never be revoked. You can even DANE-pin your existing 2030.5 head-end's certificate to DNSSEC and cut single-CA trust risk.
A near-literal drop-in for the CSIP head-end you already run. The LFDI is already the primary key of the EndDevice resource in every CSIP / Rule 21 deployment — so binding it to a /128 needs no new device provisioning. The same DANE pin anchors a DERMS/VPP head-end's TLS, an OpenADR 3.0 VTN's HTTPS endpoint, or an ISO 15118 EVSE/SECC offering — where a per-device name becomes a stable, resolvable identity that a utility, an ISO, or a peer can verify outside the vendor's cloud tenancy. Proposed integrations at the IP and cloud boundary; Whisper never reaches into the closed control layer.
The LFDI is the public fingerprint — the /128 is its cryptographic counterpart. The LFDI is a known, structured identifier flowing through every CSIP deployment; useful for interoperability, but not a secret. The /128 is bound to the device's key and the LFDI — so the LFDI alone yields nothing. You cannot go LFDI → /128 without the key, there is no enumerable directory, and RDAP/reverse-DNS return the registry object, never the device's whereabouts. Because the derivation is tenant-bound, the same device under two aggregators yields two unrelated /128s — no one can link a unit across operators.
Lifecycle, end to end — and nothing issued in the dark. Factory key → in-life dispatch → incident revoke. A module swap or repower re-keys to a new /128 and revokes the old one; a decommission or a change of aggregator is one revoke and a re-register to the new owner. Compromise one inverter and you've compromised that inverter, not the fleet — the takeover failure mode is structurally removed. Every mint and every revoke lands in a public, append-only Merkle transparency log, Ed25519-signed and Bitcoin-anchored via OpenTimestamps — an auditable issuance trail for your regulator. Honest status: tamper-evident today; independent witnessing is the next step. And you can sign a DER's telemetry to its /128 so the ISO and market settlement trust the numbers came from the real device.

"Is a first-class --lfdi flag shipping today, or is this a roadmap slide?"

Shipped & live today: derive a /128 from the device's public key with its LFDI passed as device_id — DNSSEC + DANE-EE + RDAP, verifiable trustless from the IANA root, revocable in one call. A dedicated typed --lfdi CLI/API argument is on the roadmap; the control-plane call in the 60-second proof below runs as-is.

Maps to NERC CIP-013 R1.2.3/R1.2.6 and CIP-005 R3.1/R3.2 vendor-remote-access controls, EU NIS2 Art.21, the EU Network Code on Cybersecurity, and NISTIR 7628 SG.IA/SG.AU device identification — delivered as a network primitive, not a compliance binder. See the compliance map →

Identity stops the next forgery. The graph names whoever already dispatched you.

You won't re-key the whole fleet by Monday, and there is abuse in your logs right now. So the same platform back-traces the operator behind the sessions you already logged — attribution that survives the rotation, because it fingerprints the operator and the tooling, not the ephemeral egress IP.

The answer — the graph, not another rate-limit

A live internet-infrastructure graph — 7.44B nodes and 39.3B relationships of fused BGP, DNS, WHOIS, TLS, hosting and threat intelligence, answering in under 300 ms — fingerprints the operator, not the IP. Two levers, kept honestly separate: for cloud rotation the graph clusters shared ASN, hosting and certificate lineage into one infrastructure genealogy; for a residential-proxy swarm — where a subscriber IP gives an infra graph nothing to grab — a JA4/JA3 client fingerprint travels with the tooling regardless of the exit and collapses the swarm to one operator.

And it's a question, not a signature. Express fleet enumeration directly — “one source touching N distinct DER identities in a window” — as read-only Cypher, and the graph returns the operator with a reproducible evidence chain your OT SOC, your PSIRT, your auditors and a regulator can replay. That's LFDI-enumeration and business-logic abuse caught by its shape across the fleet, not by a pattern you had to know in advance.

fleet enumeration as a query, not a signature
# ask the graph the business-logic question directly — read-only Cypher (schema illustrative) over the public graph API
$ curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
    -H 'content-type: application/json' -d '{"query":"MATCH (src)-[t:TOUCHED]->(d:DerIdentity)
    WHERE t.window = \"15m\" WITH src, count(DISTINCT d) AS lfdis
    WHERE lfdis > 50 RETURN src, lfdis ORDER BY lfdis DESC"}'
  operator <fingerprinted>   1 source → 3,412 distinct LFDIs / 15m
  egress:  AWS eu-central → GCP europe-w4 → Azure westeu   (collapsed to 1)
  ja4:     same tooling across 41 residential exits → 1 operator
  reproducible, replayable JSON evidence chain → your SIEM

"When a hijacked fleet phones home through rotating residential proxies and fresh cloud IPs, can you actually attribute it — or just rate-limit an IP and move on?"

Attribute it. Infrastructure genealogy collapses the cloud rotation; a JA4 client fingerprint collapses the residential swarm. The egress IP is the one thing we don't rely on — so the rotation that hides them from your OT SOC is exactly what the graph reads through.

And before the command even lands: op:lookups returns who resolved or RDAP-queried a DER's identity: the PTR/AAAA/TLSA and RDAP accesses against its records. It's a reconnaissance tripwire that catches an operator enumerating your fleet in recon, not a post-mortem after the dispatch; the early warning the LFDI's private registry never gave you. The read-only graph verbs your analysts run (or your agent runs for them): identify(ip) (who really operates a host, even behind a CDN) · origins(prefix) + walk(node,depth) (cluster rotating IPs into one genealogy) · history / watch (a timeline and a standing sentinel over a suspect operator). Every answer is reproducible, replayable JSON: the evidence trail for an unauthorized-dispatch finding, not a screenshot.

Identity is the cure; the graph is how you clean up what got in before it, and catch the operator who tries anyway. Detection made durable, on top of a root-cause fix.

Your OT sensor sees that a DER is misbehaving. Whisper proves who commanded it — and follows them when the IP rotates.

The OT-detection incumbents are excellent at what's on your network and whether it's behaving — necessary, and where that picture stops. Their device identity is observational: inferred from behavior, scoped to the monitored network, non-revocable off-box. Your DERMS consumes the manufacturer's 2030.5 certificate; it doesn't mint identity and inherits the life-long, no-CRL/OCSP model. Whisper adds the two layers no one else owns — exactly the two gaps the fleet-takeover attacks exploit.

OT detectionDERMS + 2030.5 PKIWhisper
OT visibility & anomaly detectionadditive feed
Publicly verifiable device identity (DNS/DANE, not a private CA)
Revocation at DNS-TTL, cross-operator
Operator attribution across rotating egress

Feeds your SIEM and PSIRT

The Splunk connector ships today — findings arrive as signed, replayable JSON mapped to CEF and ECS fields you can hand a regulator. Microsoft Sentinel, OpenCTI, and STIX 2.1 over TAXII export are on the roadmap — labeled honestly so you can plan against them.

Speaks your compliance language

Enumerate and kill any vendor device's connection in one call — direct evidence for CIP-005 R3.1/R3.2 (determine & disable active vendor remote access) and CIP-013 R1.2.3/R1.2.6. Also maps to NIS2 Art.21, the EU NCCS zero-trust/traceability, and NISTIR 7628 SG.IA/SG.AU — usable straight in an RSAW. See the map →

Additive & availability-safe

It rides existing DNS/IPv6 and adds no inline OT chokepoint. If your head-end authorizes against the DANE/verify path, that plane is built to fail open — a Whisper outage never bricks an inverter; checks degrade to your existing anchors. Anycast on AS219419, no single node in the path.

One identity fabric, every vendor

Derived from the key already in the device — no second PKI, no BOM cost, no re-flashing the fielded fleet. Whether it's an inverter, a battery gateway, or an EVSE, it's one verifiable /128 you and the ISO can both check.

Flat, predictable pricing

Per-device/year and flat — not per-transaction, not usage-metered. Against fleet-scale economics that's a line item you can forecast. Clear ROI: analyst-hours saved on disposable-IP correlation, one revoke instead of a fleet-wide reset. See pricing →

A vendor that will still be here

Real routable address space (AS219419), run by people who ran the internet's regional address registry and operated one of its root DNS servers. POC → pilot → enterprise, keyless to start.

See the full comparison →

Don't take our word for it — our API isn't in the trust path.

Two tiers, by design. No key: anyone can verify a DER's identity, resolve it, and back-trace a suspicious controller — trustless, anchored at the IANA root. Your key: bind a device to the LFDI it carries, govern its egress, revoke it worldwide.

verify & attribute — no key required
# keyless — re-derive and verify any inverter's identity, trustless
$ whisper verify --trustless 2a04:2a01:5e0::50c
  ✓ DNSSEC chain valid to the IANA root
  ✓ DANE-EE (TLSA 3 1 1) leaf matches the identity's key
  ✓ RDAP: registered under AS219419 · 2a04:2a01::/32
  identity: VERIFIED — and our own API was never trusted

# the address is the inverter — forward-confirmed reverse DNS names it
$ dig -x 2a04:2a01:5e0::50c +short
  lfdi-3f2504e0.der.example-vpp.whisper.online.

# who really operates a suspicious controller — the real graph API, a CALL whisper.identify()
$ 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> · seen across AWS / GCP / Azure
  residential swarm collapsed by JA4: same tooling, 41 exit IPs → 1 operator
provision & govern — with your key
# bind an inverter to the LFDI it already carries — one control-plane call
$ export WHISPER_API_KEY=whisper_live_xxx
$ curl -s https://graph.whisper.security/api/query -H "X-API-Key: $WHISPER_API_KEY" \
    -H 'content-type: application/json' --data @- <<'JSON'
{"query":"CALL whisper.agents({op:'connect', args:{tier:'wireguard',
   identity_public_key:'<base64 SPKI of the device key>',
   device_id:'3F2504E04F8911D39A0C0305E82C3301'}}) YIELD op, ok, result RETURN op, ok, result"}
JSON
  → identity 2a04:2a01:5e0::50c   DNSSEC + DANE-EE live   # device_id = the LFDI

# govern what the inverter may reach; see who enumerated it; then kill it if compromised
$ whisper policy set --default deny --allow derms.example-vpp.com,ota.example-vpp.com
$ curl -s https://whisper.online/ip/2a04:2a01:5e0::50c/lookups   # who checked this DER (recon tripwire)
$ whisper kill --revoke 2a04:2a01:5e0::50c   # worldwide, at DNS-TTL

Give every DER an identity it can prove.

The address is the inverter — routable, DNSSEC-anchored, bound to the LFDI it already carries, revocable worldwide in one call. Keyless to try, one call to provision, one more to revoke. The grid-API abuse that no rate-limit ever caught simply runs out of forgeries.

Or run whisper verify --trustless right now.