Threat Model
Trust boundaries, data flow, assumptions, and the privacy guarantees Heron makes by construction.
What Heron is
Heron is a passive DNS observer. It runs a local DNS server that forwards every query transparently to upstream resolvers and logs what it sees. It does not block, redirect, or filter. The buzzer is an alert, not enforcement. There is no cloud component - the device works entirely offline after setup.
Trust boundaries
Four boundaries exist in the system. Each is defended by a different mechanism.
| Boundary | Channel | Defence |
|---|---|---|
| Browser ↔ Device (setup) | USB WebSerial, 115200 baud | Cryptographic challenge-response (ECDSA P-256). Browser verifies device certificate against embedded root key. |
| Dashboard / CLI ↔ Device (ongoing) | LAN HTTP, port 8080 | None. LAN presence is the only access control. No authentication, by design. |
| Device ↔ Upstream DNS | UDP 53, forwarded to 1.1.1.1 / 8.8.8.8 | Transparent forwarding. Queries are observed, not modified. |
| Device ↔ Any external server | None | No server exists. The device makes no outbound connections beyond DNS forwarding. |
What the device identity system prevents
- Counterfeit devices. A fake cannot produce a valid signature without the private key burned into the chip during manufacturing.
- Replay attacks. The PWA sends a fresh 32-byte random nonce for every setup. A captured signature cannot be reused.
- Server compromise. There is no server. Device verification runs entirely in the browser against a public key embedded in the page.
- MITM on provisioning. Wi-Fi credentials are written over USB after verification. Nothing is transmitted over a network.
What it does not prevent
- Physical extraction of the private key via chip decapsulation. Requires specialised lab equipment. Out of scope for a consumer device.
- Firmware reflash with attacker code. Phase 1 stores keys in OTP so identity cannot be cloned, but firmware files on flash are not signed. Full secure boot is deferred to Phase 2.
- PWA compromise. A modified onboarding page could skip verification. The PWA is hosted on GitHub Pages; the root public key is embedded in source.
Privacy guarantees
The privacy claim is literal: nothing phones home. DNS query logs stay on the device in /dnslog.json, cached to flash. The setup page makes zero network calls - the cryptographic verification uses Web Crypto against an embedded public key. The dashboard talks to the device over the LAN. No account, no email required, no cookies, no analytics, no third-party scripts on the marketing site.
If you do not believe the claim, read the firmware. It is open source under the MIT license.
Key storage
Device private keys live in the RP2350's one-time-programmable (OTP) memory. A custom MicroPython C module (machine.OTP) provides read and write access to the customer data region. OTP bits go 0→1 only - once burned, the private key is locked in the chip and cannot be read back via USB.
Flash file storage at /keys.bin exists as a fallback for builds without the OTP module. The manufacturing script refuses to ship a device that ended up on the flash backend.
Secure boot: phased
| Phase | State | What it stops |
|---|---|---|
| Phase 1 - OTP keys | Current. Shipped. | Key cloning. A stolen device gives up hardware, not keys. |
| Phase 2 - Full secure boot | Deferred until volume production. | Firmware tampering. Signed UF2s, frozen modules, SECURE_BOOT_ENABLE on production devices only. |
Phase 2 requires a separate secp256k1 firmware signing key - the RP2350 boot ROM uses secp256k1, not P-256. All four OTP key hash slots are provisioned at manufacturing so rotation does not require a hardware recall.
Root key compromise
The root private key never leaves the manufacturing machine. Physical security of that machine is the primary control. If the root key is compromised, recovery requires generating a new key pair, embedding the new public key in the PWA, and re-provisioning affected devices. To make rotation possible without a PWA redeploy, four root public keys are embedded from day one. If key 0 leaks, the PWA already trusts key 1.