# A hack nobody has noticed yet (/invest/incidents/hack-unnoticed)

This is the hardest case. A thief takes cash out of a protocol, but the protocol's internal records (its "books") still say the money is there. The adapter, the small program that reports what the vault's position in that protocol (its **leg**) is worth, reads those books, so it keeps reporting full value. The vault sees nothing wrong, and nothing on chain can tell it otherwise.

The figures in Examples 2 and 3 were measured in automated tests on copies of each real protocol's mainnet programs and accounts, and are rounded.

## Why it matters [#why-it-matters]

While the theft is hidden, every withdrawal is paid at the old, too-high value. Each person who leaves takes out a little more than their share was really worth. When the theft is finally discovered and the leg is marked down, that extra amount is missing, and the people who stayed pay for it.

In short: during an unnoticed hack, leaving early is rewarded and staying is penalised. The vault cannot prevent this on its own, because it has no honest number to use. What it can do is slow the outflow, and the guardian can stop it with a **mark** (a ceiling on the leg's value, see [A hack the protocol has not reported](/invest/incidents/hack-discovered)) as soon as anyone knows.

## How the overpayment works [#how-the-overpayment-works]

```mermaid
flowchart LR
    T[Thief takes cash] --> B[Protocol books unchanged]
    B --> R[Adapter reports full value]
    R --> W[Withdrawals paid at full value]
    W --> O[Leavers overpaid]
    D[Hack discovered] --> M[Guardian marks the leg]
    M --> L[Loss booked on the holders who stayed]
    O -.-> L
```

*Figure: the theft is invisible to the vault until someone marks the leg, so the overpayment to early leavers ends up on the holders who stayed.*

## Example 1: the basic case [#example-1-the-basic-case]

Suppose a vault has 1,000 USDC of Junior, held by June, and 4,000 USDC of Senior split between two holders, Alice and Bob, with 2,000 each. Each share is worth 1 USDC. The leg holds 3,000 USDC and the rest is idle cash.

1. A thief takes 1,800 USDC from the protocol. The leg is really worth 3,000 − 1,800 = 1,200, but it still reports 3,000.
2. Alice withdraws all her 2,000 Senior shares. The vault pays her 2,000 USDC from idle cash.
3. The hack is discovered. The guardian marks the leg at its real value of 1,200.
4. The 1,800 loss is booked: Junior loses all its 1,000, and Senior loses the remaining 800. Only Bob is left in Senior, so Senior falls from 2,000 to 1,200 and records an impairment (a loss tracked for repayment) of 800. The vault is **frozen**: no withdrawal can be funded until Senior is repaid.

What would have been fair? Senior's real loss was 1,800 − 1,000 = 800, so Senior was really worth 4,000 − 800 = 3,200, and Alice's half was worth 1,600. She received 2,000, which is **400 USDC too much**. Bob carries those 400 on top of his own fair 400 share of the loss.

## Example 2: the same theft on the real protocols [#example-2-the-same-theft-on-the-real-protocols]

In these tests the thief takes all the cash a protocol holds. The vault is set up with a thin Junior: 250 USDC, which is 5% of the 5,000 total and the lowest minimum coverage the program allows. Alice holds 1,000 USDC of Senior and Bob 3,000. The leg holds 3,000 USDC and 250 + 4,000 − 3,000 = 1,250 USDC is idle.

What the theft really costs depends on how each protocol keeps its money:

| Protocol | What the 3,000 USDC leg really lost | Why |
| --- | --- | --- |
| Kamino | about 292 USDC | A lending market loses its cash, but borrowers still owe the rest. |
| Jupiter Lend | about 304 USDC | Same as Kamino. |
| Huma | about 11 USDC | The pool's cash is a small part of its assets. |
| Hastra | about 0.04 USDC | Same as Huma. |
| Solstice | 3,000 USDC | All of the backing sits in one place, and the thief takes it. |

*Table: measured in tests and rounded; the same theft costs a lending leg about 10%, a credit pool almost nothing and Solstice everything.*

With Solstice, Junior's 250 is lost and Senior loses 3,000 − 250 = 2,750. Alice holds a quarter of Senior (1,000 of 4,000), so if she leaves first at full value, a quarter of that loss, 2,750 ÷ 4 ≈ **687 USDC**, leaves with her. Bob carries it.

Whether anything raises an alarm also depends on the protocol. When the executor, the service that moves the vault's cash into and out of legs, tries to take money out of the robbed leg:

| Protocol | Result of an exit | What it means |
| --- | --- | --- |
| Kamino | Fails (`InsufficientLiquidity`) | Nothing moves. The error is the alarm. |
| Jupiter Lend | Fails (`InsufficientBalance`) | Nothing moves. The error is the alarm. |
| Huma | Fails | Huma refuses instant exits at its current liquidity anyway, robbed or not. |
| Hastra | Succeeds by selling the token | The exit sells the token on a market the theft did not touch. The theft stays hidden. |
| Solstice | Succeeds by selling the token | Same as Hastra. |

*Table: an exit through the robbed protocol fails loudly, but an exit that sells the token on a market hides the theft.*

## Example 3: new money sent into a robbed protocol [#example-3-new-money-sent-into-a-robbed-protocol]

If the executor keeps investing in the robbed leg, the new money is exposed too, because it buys in at the protocol's book price.

| Protocol | What 500 USDC put in is worth afterwards |
| --- | --- |
| Kamino | Nothing moves: Kamino's own check after a deposit finds its cash short of its books and refuses. |
| Jupiter Lend | about 449 USDC |
| Huma | about 498 USDC |
| Hastra | about 500 USDC |
| Solstice | about 0.36 USDC |

*Table: measured in tests and rounded; only Kamino refuses new money into a robbed reserve, and elsewhere the new money takes its share of the theft.*

## The Senior outflow brake [#the-senior-outflow-brake]

**What it is.** The brake is an optional limit on how much USDC Senior holders can take out of the vault in a 24-hour window. The curator sets it per vault as a share of Senior's value, in basis points (one basis point is 0.01%, so 10,000 basis points is 100%). The program's default is 0, which means the brake is off. The curator can turn it on with a queued `SetRiskSettings` change, up to 10,000 basis points.

**Why it exists.** During an unnoticed hack, the brake slows a run, so less money leaves at the wrong price before the hack is discovered.

**How it works.** When a Senior request is funded with `fund_withdrawal`, it can take at most `(Senior's value + already paid in this window) × limit ÷ 10,000` in the current window. The window restarts when 24 hours have passed since it began. When the window's room is used up, funding fails with `OutflowLimitReached`. The rest of the request stays in the queue and can be funded in the next window.

**Example.** The same Solstice theft as in Example 2, with the brake at 10% (1,000 basis points). Alice asks for her 1,000.

1. Day 1: she is paid 4,000 × 10% = 400.
2. Day 2: she is paid 10% of the 4,000 − 400 = 3,600 left, which is 360.
3. The theft is discovered, the guardian marks the leg, and the vault freezes. The rest of her request waits.

Each payment took 10% of Senior's book value while the whole hidden 2,750 loss was still inside it, so each payment carried 10% of that loss: 2 × 275 = **550 USDC**, a fifth of the Senior loss instead of a quarter. Bob saves about 687 − 550 = 137 USDC.

The takeaway is that the brake reduces the damage but does not prevent it. It only helps if someone discovers the hack while the brake is holding withdrawals back.

## Example 4: the later leaver takes more per share [#example-4-the-later-leaver-takes-more-per-share]

Suppose the vault holds 4,000 USDC of Senior and the theft is discovered five days after it happens. Alice leaves with 500 on day 1 and Bob with 500 on day 3. Each is paid at book value, while the whole hidden loss stays behind.

- Alice's 500 is one eighth (500 ÷ 4,000) of Senior, so she takes 12.5% of Senior's loss with her.
- When Bob leaves, Senior's book value is 3,500 but it still contains the whole loss, so his 500 takes 500 ÷ 3,500, about 14.3%, of the loss.
- The 3,000 of Senior still in the vault holds three quarters of the shares, so its fair part of the loss is three quarters. It carries the whole Senior loss on the books instead.

## How a hidden hack is caught [#how-a-hidden-hack-is-caught]

The on-chain program cannot see an unnoticed theft. Akashi runs an off-chain balance monitor that, at regular intervals, compares the tokens each protocol really holds with what the protocol's own records say it should hold, and warns the guardian when they differ. The guardian then marks the leg ([A hack the protocol has not reported](/invest/incidents/hack-discovered)).

- For Kamino, Jupiter Lend and Solstice, the records name the cash the protocol should hold, so the check compares the two directly.
- For Huma, Hastra and OnRe, part of the backing is lent out or held off chain. The check looks for cash that left since the last check and that the records do not explain. A protocol's own operators moving cash off chain looks the same, so these alerts say so.

A gap counts only when it is larger than both 0.5% of what the records say and 1,000 USDC. For example, a protocol whose records show 10,000,000 USDC needs a gap above 50,000 USDC (0.5%), and one whose records show 100,000 USDC needs a gap above 1,000 USDC, because 0.5% of it is only 500. Warnings go to the guardian through a webhook or Telegram, and are always logged.

## Advanced details [#advanced-details]

- The overpayment in the tests is measured by tracking, for each holder, what they were paid against what their shares were really worth.
- OnRe is not covered on this page: OnRe sets its net asset value (NAV) itself, so a theft there shows up only as a lower NAV, which the vault books as [an honest loss](/invest/incidents/honest-loss).
- The `Vault` account records when the brake's current window started and how much Senior has taken out in it. A funding that the brake limits can be partial; the request stays open for the rest.
