OAK — OnChain Attack Knowledge

Worked example · 2026-09

XRPH Wallet — a self-custody wallet sent the user's seed phrase to the vendor's own server every time someone staked, and 4,011 accounts were emptied — XRP Healthcare (XRPH Wallet) / XRP Ledger — 2026-09-03

Loss
~$452,000 across 4,011 wallets — approximately 267,000 XRP plus associated token balances. Unauthorised transactions began 2026-09-03 from 22:07 UTC. XRP Healthcare traced proceeds to a single Ethereum wallet and approached exchanges about freezing. Users were told to stop using XRPH Wallet while the vendor investigated. The root cause is not fully closed: independent review attributes the compromise to seed phrases transmitted during staking, but roughly 70% of the drained wallets had never staked, which points to at least one additional exposure path that has not been publicly identified.
OAK Techniques observed
OAK-T11.012 (Server-side Raw Private-Key Storage — primary, and an extension of the Technique beyond its trading-bot origin. Review of XRPH Wallet v8.0.15 found that the staking function transmitted the user's seed phrase to an XRP Healthcare server when staking or unstaking. Nothing was breached to make this happen; the application was built to send the secret, which converts a nominally self-custody wallet into a custodial one without telling the holder. See techniques/T11.012-server-side-raw-private-key-storage.md). A second, independent exposure is on the record: the same review found wallet seeds stored unencrypted in the application's local database, though reaching that data requires device control or elevated malware permissions and it is not established as the vector here. OAK-T11.006.001 (User-Initiated Plaintext Seed Storage) explicitly does not apply — the plaintext storage was application-initiated, not a user choice, which is a different accountability shape and is noted below as a taxonomy gap. OAK-T11.002 (Wallet Software Distribution Compromise) also does not apply: the official build was the vulnerable build, with no tampering in the distribution path.
Attribution
unattributed. Proceeds consolidated to a single Ethereum wallet; no named individual, group, or link to a tracked OAK actor. Independent analysis is credited to security researchers including former Ripple developers, who flagged the wallet's design publicly.
Key teaching point
Any code path that needs the seed to work is a custody decision, and it is usually made by a feature team that does not know it is making one. Staking on the XRP Ledger requires a signature, and the shortest way to ship that feature is to send the secret somewhere convenient and sign server-side. That single implementation choice moved 4,011 users' custody to a vendor server while the product continued to present itself — and be understood by holders — as self-custody. The reusable control is architectural and testable: the seed must never leave the signing boundary, and the boundary must be enforced by a test that fails the build, not by a convention. A wallet should be able to demonstrate, on demand, that no outbound request in any feature path carries key material — and if a feature genuinely cannot be built that way, the correct outcome is that the feature does not ship, not that custody quietly changes.

Summary

XRPH Wallet is the wallet application for XRP Healthcare, an XRP Ledger project. It is presented as self-custody: the user holds the seed, the user holds the funds.

Independent review of version 8.0.15 found that the wallet's staking function transmitted the user's seed phrase to an XRP Healthcare server during staking and unstaking operations. The same review found seeds stored unencrypted in the application's local database — a separate exposure requiring device access rather than a network path.

Beginning 2026-09-03 at 22:07 UTC, unauthorised transactions drained 4,011 wallets of about 267,000 XRP and associated tokens, roughly $452,000 in total. Proceeds were consolidated to a single Ethereum wallet. XRP Healthcare told users to stop using the wallet and contacted exchanges about freezing funds.

The public account does not fully close. Nearly 70% of the drained wallets had never staked, so they should never have transmitted a seed through the staking path at all. Either another code path exposed key material, or the local unencrypted storage was reachable more broadly than assumed, or the two findings are symptoms of a wider handling problem. OAK records the confirmed design finding and the unexplained residual as separate facts, and does not reconstruct a mechanism the evidence does not support.

Timeline (UTC)

When Event OAK ref
(standing) XRPH Wallet v8.0.15 transmits the user's seed phrase to an XRP Healthcare server during staking / unstaking standing T11.012 condition
(standing) Wallet seeds stored unencrypted in the app's local database (second, independent exposure)
2026-09-03 22:07 Unauthorised transactions begin across XRPL accounts (exploitation)
2026-09-03 → 09-04 4,011 wallets drained — ~267,000 XRP plus tokens, ~$452,000; proceeds consolidated to one Ethereum wallet (extraction)
after XRP Healthcare tells users to stop using the wallet; contacts exchanges about freezing (operator response)
after Independent review — including former Ripple developers — publishes the seed-transmission and plaintext-storage findings; ~70% of drained wallets had never staked, leaving the vector partly unexplained (external analysis; open question)

What defenders observed

  • The vulnerability shipped as a feature, so no security process was looking at it. There was no intrusion, no malicious dependency, and no tampered build. A staking capability was implemented in the way that was easiest to make work. Threat models aimed at attackers reaching the seed do not fire when the application sends it on purpose.
  • A single outbound-traffic check would have found it in minutes. Inspecting the app's network requests for key material is a basic test, requires no source access, and is exactly what the independent reviewers did — after the money was gone. For any wallet, "no request body ever contains seed-derived material" is a one-line invariant and belongs in CI.
  • The unexplained 70% is the most important open fact. If most drained wallets never used the vulnerable path, the disclosed finding does not account for the incident. Publishing a root cause that the loss distribution contradicts leaves every remaining user unable to judge whether they are still exposed.
  • Two secrets-handling defects in one build is a pattern, not a coincidence. Sending seeds over the network and storing them unencrypted locally are the same underlying assumption — that the seed is ordinary application data — expressed in two places. Where that assumption exists, it is rarely confined to the paths that happen to get audited.
  • The compromise scaled the way custodial compromises do, because the architecture was custodial. 4,011 users in one event is not a phishing outcome; it is what happens when one server holds many secrets. The product's self-custody framing meant users carried a custodial risk they had not agreed to and could not see.
  • XRPL's account model bounded nothing here. With the seed, an attacker has full authority over the account. Ledger-level protections — regular keys, multi-signing, deposit authorisation — exist and would have limited the blast radius, but they are opt-in features that a wallet holding the master seed is in no position to enforce.

Public references

Discussion

T11.012 was written from the DEXX trading-bot cohort (2024-09), where the anti-pattern is at least legible: a platform that trades on your behalf while you sleep needs signing authority, holds raw keys server-side to get it, and turns one database breach into every user's loss. The bargain is bad but visible. XRPH is the same architecture arrived at by accident, inside a product that advertises the opposite. No one decided XRP Healthcare should hold 4,011 users' keys. A staking feature needed a signature, the seed was the nearest way to produce one, and custody moved.

That makes this the more dangerous shape, and probably the more common one. A trading-bot user has some notion that the platform acts for them. A self-custody wallet user has been told, correctly as far as they can observe, that the vendor cannot touch their funds — and there is no interface element, permission prompt, or disclosure that would reveal otherwise. The user's threat model and the software's architecture diverged silently, and only the architecture was load-bearing. OAK should expect this shape wherever a self-custody wallet grows server-dependent features: staking, swaps, gasless transactions, account recovery, cross-chain routing. Each is a request to sign something, and each invites the same shortcut.

Two things are unresolved and should be recorded as such rather than smoothed over. First, the 70% of drained wallets that never staked — the disclosed vector does not explain the loss distribution, and no fuller account has been published. Second, a taxonomy gap: OAK has T11.006.001 for user-initiated plaintext seed storage (the user pastes a seed into a notes app or a screenshot), and nothing for application-initiated plaintext seed storage, where the software persists or transmits the secret without the holder's involvement or knowledge. The distinction matters for defenders and for accountability — one is addressed by user education, the other only by vendor engineering and app-store review — and this incident supplies both halves at once. Proposed as a candidate for TAXONOMY-GAPS.md pending a second anchor.

Techniques demonstrated (3)