<!-- https://zunderlabs.com/docs/security/threat-model · Markdown version of the page -->

# Threat model

What each part of the Zunder stack can and cannot do, and what happens when the bot, the relay, the website or a key is compromised, or a request is replayed.

This page says plainly what Guard protects against and what it does not. It covers Guard as planned for 1.0; where a protection exists in code today, the page says so.

## The parts, and what each can do

| Part | Runs on | Holds | Can | Cannot |
|---|---|---|---|---|
| Your bot or agent | your machine | a Guard client key | send orders to Guard | reach Hyperliquid with that key; exceed your limits |
| Guard (planned) | your machine | the API wallet key, the journal | sign and send orders within your limits; close positions | withdraw or transfer funds (an API wallet cannot); approve keys or builder fees |
| API wallet key | inside Guard | — | trade your account | withdraw, transfer, approve |
| Your main wallet | your wallet app | your funds' key | everything | — Guard never asks for it |
| Relay (planned) | our server | nothing | forward, delay or drop requests | sign, place orders, read keys |
| zunderlabs.com | your browser | nothing of yours | read public Hyperliquid data; run the engine in your tab | connect a wallet, sign, see a key |
| Hyperliquid | the venue | your funds | everything a venue can | — out of scope here |

## Threats

### 1. The bot is compromised

A bug, a malicious plug-in or a prompt injection makes your bot or agent send orders you did not want.

- **Guard limits the damage** to what your rules allow: each trade at most 2% at its stop, all stops together 6%, 5x exposure, the daily loss stop and the drawdown halt (defaults). It never has the API wallet key, so it cannot go around Guard.
- **What remains:** losses within the limits, every day until the drawdown halt. A bot can also buy an illiquid market at a bad price, from an accomplice on the other side, within its size limit. The [market allowlist](https://zunderlabs.com/docs/concepts/rules#a-market-allowlist) is the defence: allow only markets you trade. Your limits are the ceiling of what a compromised bot costs you.
- **Exits pass.** A compromised bot can close your positions at a bad moment. Guard does not block exits, by design.

### 2. The relay is compromised (planned component)

- **Bot requests** carry a client-key signature and a nonce. A compromised relay can delay or drop them. It cannot forge, replay, or push them past your limits (`docs/decisions.md`, 6 Oct 2026).
- **TradingView alerts** cannot be signed by TradingView. They carry a secret in their text, which the relay sees. A compromised relay could send its own alerts, which still pass all your rules. **Open design point:** how to bind alerts so that a relay cannot create them.
- **What remains:** missed alerts, delayed orders. Do not run a bot whose safety depends on the relay being up.

### 3. The website is compromised

zunderlabs.com is static. It holds no key, connects no wallet and signs nothing; Backtest, Watch and Live market read public data only.

- A compromised site could show false results, or a page that asks for a key. **We never ask for a key, a seed phrase or a signature on the website.** A page that does is not ours.
- It could serve a tampered download link. That is why releases are signed and their provenance is published: [verify a release](https://zunderlabs.com/docs/deploy/verify) before you run it.
- A planned browser Guard (behind the relay) would hold an API wallet key in your tab. A compromised site could steal it. That is the reason the browser Guard is for trials, and bots running around the clock use the local Guard.

### 4. Key theft

- **API wallet key stolen** (from your machine or server): the thief can trade your account like a compromised bot, but **without** your limits, because they would not go through your Guard. They cannot withdraw. Remove the API wallet in the Hyperliquid app at once ([API wallets](https://zunderlabs.com/docs/concepts/api-wallets#if-you-think-a-key-has-leaked)). Keep only what you are willing to lose on that account.
- **Client key stolen:** the thief can send orders through your Guard, within your limits. Revoke the client key in Guard. Hyperliquid never knew it.
- **Main wallet key stolen:** out of Guard's reach. Guard never asks for it.

Zunder's own runner reads its key from standard input only, wipes the buffer after parsing, refuses a terminal, disables core dumps, and never prints, logs or writes the key (`docs/testnet.md`, "The key"). Guard is planned to keep the same discipline; how it stores the key between restarts is not decided.

### 5. Replay

Someone records a valid request and sends it again.

- **To Guard:** every client request carries a nonce; Guard refuses a nonce it has seen or one that is too old (planned).
- **To Hyperliquid:** Guard signs every order with a fresh nonce. Hyperliquid's own nonce rules apply.
- **Across networks:** a testnet signature is rejected on mainnet and the reverse (phantom agent source `"b"` / `"a"`, pinned against the official Python SDK's vectors in `crates/zunder-exec/src/hyperliquid/signing.rs`).
- **Late arrival:** Zunder's entries carry an expiry (10 s, at most 30 s) so a request held up in the network cannot land long after it was meant (`docs/testnet.md`). Guard is planned to keep this.

### 6. The journal is tampered with

The journal is checksum-chained: a changed, removed or reordered line is detected and trading stops. An older complete copy put in its place **cannot** be detected from the file ([The journal](https://zunderlabs.com/docs/concepts/journal#what-it-cannot-detect)).

## Out of scope

- Hyperliquid itself: its matching, liquidations, outages, bridge or validators.
- Your operating system and anything with root on your machine. Root can read any key and edit any file.
- Market risk within your limits. Guard enforces limits; it does not make trades good.
- Gaps through a stop. A stop can fill far beyond its trigger.

## Reporting

Found a way around any of this? [Report it](https://zunderlabs.com/docs/security/reporting).
