# The equipment-API-abuse cure

**A reverse-engineered farm-data API plus an OAuth grant that is portable to any IP is the entire data-harvesting problem. It has an OWASP name, BOLA, because the token authenticates a *claim*, never the machine on the other end.**

Whisper closes it by making the address *be* the machine: a routable IPv6 `/128` derived from the key already sitting in the machine, DNSSEC-anchored and DANE-pinned, that no broker can forge and one owner-thrown call can revoke worldwide. A harvested grant with no device key behind it authenticates to nothing, and the farmer finally gets a data trail with a network fact behind it.

## The abuse, at class level

It is not a breach. Your farm-data API is used exactly as it was built, at platform scale, by an operator who was never your customer.

A third party reverse-engineers the platform's apps and partner docs, increasingly with the help of an LLM, until it holds the exact calls the sanctioned integrations make. It then authenticates the same ways they do: a phished grower login, a static partner key, or an OAuth **bearer token that travels to any IP**, with an access token that lives about twelve hours and a refresh token that lives a year. From there it is contract-less, low-and-slow polling, indistinguishable from a real integration because it *is* the integration's protocol. And the reach is enormous: a single major farm-data platform touches 400M+ engaged acres, and cross-brand exchanges now move machine data between four OEM and FMIS clouds.

> The root cause has a name: **OWASP broken authentication / BOLA** (API1:2023). The token authenticates a *claim* but never proves *which machine* is on the other end. A researched disclosure showed the ceiling of a single flaw of this class: owner name, home address, equipment ID and VIN, reachable from nothing but a guessable identifier.

Two properties make it invisible at the network layer: a legitimate grower is *one IP to one farm*; the abuser is *one operator to thousands*, holding valid credentials, rotating egress across clouds or a residential-proxy swarm. And the wound lands on the industry's one sacred promise: "farmers own their farm data" is unenforceable without a per-party network identity. A data-sovereignty exposure, not only a security one.

## The reframe: the address is the machine

Detection will always be a step behind a credential that is genuinely valid. The strictly-stronger move is to change what the backend 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](/docs/dane) pinned (`3 1 1`), and RDAP-registered.

Point it at the machine: derive each machine's (or each ECU's) `/128` from its secure-element / TPM public key, with the **17-character equipment PIN** (and optionally an implement/ECU serial) as the domain separator. Deterministic, tenant-bound, unlinkable across fleets. The backend then authorizes on the machine's *pinned identity*, not a stealable token.

> **The PIN is the public index: the `/128` is its cryptographic counterpart.** The PIN is stamped on the frame and printed in every auction catalogue; that is what the attacker weaponizes. But PIN alone yields nothing: you cannot go PIN → `/128` without the key, there is no enumerable directory, and RDAP / reverse DNS return the registry object, never the machine's whereabouts.

## What changes

| The abuse today | Why it dies under identity |
|---|---|
| **One IP → a whole co-op** | You cannot present thousands of machine-identities whose device keys you do not hold. Every forgery is a DNSSEC / DANE inconsistency any verifier catches with stock tools. |
| **Rotate egress across clouds / residential proxies** | Identity is not the source IP. The *last IP* was never the credential. |
| **Replay a harvested grant or partner key** | The credential has no device key behind it. State-changing commands terminate mutually-authenticated to the target machine's `/128` (the machine co-signs). BOLA / IDOR lose their leverage. |
| **Consent with no trail behind it** | Every sanctioned data consumer is one verifiable `/128` with a per-identity access log: a record you can show the farmer. |
| **Blast radius on compromise** | One `revoke`, thrown by the owner and publicly checkable, tears down the `/128`, its PTR, and its DANE pin worldwide at DNS-TTL speed. Compromise one ECU and you have compromised *that ECU*, not the fleet. |

## Provision a machine identity

One control-plane call to `POST https://graph.whisper.security/api/query` with your `X-API-Key` header. Pass the machine's **public** key material (base64 SPKI) and its PIN; get back the deterministic `/128` and a WireGuard config.

### The call

```
CALL whisper.agents({op:'connect', args:{
  tier:'wireguard',
  identity_public_key:'<base64 SPKI of the machine key>',   # its secure-element / TPM public key
  vin:'1AGCM82633A004352'                                   # the 17-character equipment PIN rides here today
}}) YIELD op, ok, status, result, error
  RETURN op, ok, status, result, error
```

**Over stock tools.** `jq` builds the JSON body so the Cypher's own quotes never fight the shell:

```sh
Q="CALL whisper.agents({op:'connect', args:{tier:'wireguard', \
   identity_public_key:'AAAAC3NzaC1lZDI1…SPKI', vin:'1AGCM82633A004352'}}) \
   YIELD op, ok, status, result, error RETURN op, ok, status, result, error"

curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_xxx" \
  -H "content-type: application/json" \
  --data "$(jq -nc --arg q "$Q" '{query:$q}')"
```

### The response

```
address        2a04:2a01:1c0::a6f1
fqdn           pin-1agcm82633a004352.farm.<tenant>.agents.whisper.online
ptr            pin-1agcm82633a004352.farm.<tenant>.agents.whisper.online
state          active                       # DNSSEC + DANE-EE (3 1 1) live at provision time
wireguard_config   [Interface] …            # source the machine's traffic from its own /128
```

### Idempotency and errors

| You send | You get |
|---|---|
| The **same** device key + PIN again | The **same** `/128`: idempotent, safe to retry, safe to run on every boot. |
| The same device key with a **different PIN** on your tenant | `409 Conflict`: a device key binds to exactly one machine. |
| A **non-string** identifier | `400` with an actionable `detail`, never an opaque `500`. |

> **On the CLI:** `whisper create --register` mints a generic agent identity, and `whisper verify` / `whisper policy` / `whisper logs` / `whisper kill --revoke` drive the rest. The equipment-specific `--pin` flag is not shipped yet; provision machines through the control-plane call above, which is live today.

### Revoke, worldwide, owner-thrown

```
# the control-plane op…
CALL whisper.agents({op:'revoke', args:{agent:'2a04:2a01:1c0::a6f1'}})
# …or the CLI
whisper kill --revoke 2a04:2a01:1c0::a6f1

# now prove it, worldwide, at DNS-TTL speed:
dig -x 2a04:2a01:1c0::a6f1 +short                       # -> nothing
curl -s https://whisper.online/verify-identity/2a04:2a01:1c0::a6f1
# -> {"is_whisper_agent": false, ...}
```

The accountable kill-switch, never a covert lockout.

## Verify it: keyless, no account

```sh
# no key, no account: re-derive and verify the machine's identity, trustless to the IANA root
whisper verify --trustless 2a04:2a01:1c0::a6f1

# or with only curl: the keyless full-chain verdict
curl -s https://whisper.online/verify-identity/2a04:2a01:1c0::a6f1
# { "is_whisper_agent": true, "dane_ok": true, "jws_ok": true, "evidence": { ... } }

# the address IS the machine: forward-confirmed reverse DNS names it
dig -x 2a04:2a01:1c0::a6f1 +short
# pin-1agcm82633a004352.farm.<tenant>.agents.whisper.online.

# the registry object for the /128: RDAP, typed JSON
curl -s https://whisper.online/ip/2a04:2a01:1c0::a6f1 | jq '.handle, .parentHandle'
```

A regulator, or a farmer, can verify a machine *outside* your cloud's tenancy. Full mechanics: [Verify an agent](/docs/verify) and [DANE & TLSA](/docs/dane).

## Name what already got in

```sh
# who really operates a host, even behind a CDN 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(\"203.0.113.10\")"}'
```

The read-only verbs (`identify`, `origins`, `walk`, `variants`, `history`) run over that one endpoint against a live internet-infrastructure graph. Every answer is reproducible, replayable JSON: the paper trail a GDPR or Data-Act finding needs, and the receipt a farmer's data-sovereignty question deserves. See [Graph & cognition](/docs/graph-api).

## Where it fits: standards, SIEM, integrations

**Compliance.** The per-`/128` egress logs and the attribution graph are ready-made continuous-monitoring and forensics evidence for **ISO 24882** (DIS registered October 2025, ISO/TC 23/SC 19); forge-proof identity and owner-thrown revocation give **AEF Guideline 040**'s ISOBUS security principles their missing public-crypto counterpart at the IP boundary; the **EU Data Act** makes each authorized party one `/128` plus DANE plus a who-accessed-what trail, which is also exactly the record **Ag Data Transparent** presupposes. The mapping lives in [Agriculture compliance](/docs/industries/agri/agriculture-compliance).

> **Shipped vs roadmap.** The **Splunk**, **Microsoft Sentinel** and **OpenCTI** connectors ship today. **Roadmap**, labelled as such: **STIX 2.1 over TAXII** export, and sector-ISAC-ready sharing formats for food & agriculture.

**Integrations (proposed, not vendor-endorsed).** Whisper anchors the cloud and IP boundary, never the implement bus, the drone broadcast, or the safety path: farm-data platforms (allowlist per-consumer `/128`s), ISOBUS / AEF 040 (NAME on the bus, provable `/128` on the wire), cross-brand exchange (identity that survives the brand boundary), secure element / TPM (the derivation input).

And it is built to **fail open**: a Whisper outage never parks a machine. Harvest doesn't wait for anyone's uptime.

## Next

- [Equipment & ECU identity](/docs/industries/agri/equipment-identity): how the `/128` is derived from the device key and PIN, in depth
- [Control plane](/docs/control-plane): the full `whisper.agents` op set the provisioning call belongs to
- [Agriculture compliance](/docs/industries/agri/agriculture-compliance): the clause-by-clause evidence mapping

---

← [Equipment & ECU identity](/docs/industries/agri/equipment-identity) · [Agritech integrations →](/docs/industries/agri/agritech-integrations)
