Ledger Connect Kit npm Supply-Chain Wallet Drainer (2023-12-14)
- Name: Ledger Connect Kit npm supply-chain wallet drainer
- Date: 2023-12-14
- Protocol: Ledger Connect Kit / downstream dApps using
@ledgerhq/connect-kit - Chain: Primarily Ethereum and other EVM chains reached through compromised front ends
- Category: front-end compromise / supply-chain compromise / approval phishing / wallet-permission drain
- Loss: at least
$600,000, with some same-day public estimates closer to$680,000; Ledger described the victim set as low-volume and Tether froze part of the exploiter’s USDT during the response - Summary: Ledger’s hardware wallets and Ledger Live were not breached directly. Instead, an attacker phished a former employee, used an NPMJS session token tied to that still-authorized account, published malicious
@ledgerhq/connect-kitversions1.1.5,1.1.6, and1.1.7, and let downstream dApps load the poisoned package through Ledger’s runtime loader and CDN path. Any wallet connecting through those front ends — not just Ledger wallets — could then be shown attacker-controlled signing prompts. The injected Angel Drainer payload used rogue WalletConnect plumbing plus approval / permit / multicall drain paths to steal user assets across a wide set of legitimate dApps. Inside the release-integrity branch, Ledger is the cleansame real site, different loader-resolved bytescousin: the downstream domain stayed genuine while the wallet-connection bytes resolved at page load drifted underneath it. - Trigger / entry point:
- On
2023-12-14, a former Ledger employee was phished and the attacker obtained a still-valid NPMJS publishing session / API credential tied to that offboarded account, bypassing the protection Ledger expected from 2FA alone. - Ledger said the employee’s internal Ledger access had already been revoked, but the employee’s NPMJS access had not been manually removed during offboarding.
- The attacker published malicious
@ledgerhq/connect-kitversions1.1.5,1.1.6, and1.1.7at roughly09:49,10:44, and11:37CET. - Ledger’s
connect-kit-loadercomponent was explicitly designed to let dApps load Connect Kit at runtime from Ledger’s distribution path / NPMJS-backed CDN so developers could pick up the latest version without shipping a fresh build. - Ledger said most dApps had integrated through that loader path rather than pinning and self-hosting one audited local artifact.
- That meant the attacker did not need to compromise each dApp individually. Poisoning the shared package let the malicious JavaScript fan out across many legitimate front ends.
- On
- Root cause:
- The decisive failure was a software-supply-chain control failure in wallet-connection infrastructure, not a Solidity bug in one downstream protocol.
- Per Ledger’s report, the attacker did not gain access to Ledger’s code repository, Ledger internal infrastructure, or the downstream dApps themselves; the decisive control point was package publication and runtime distribution.
- Ledger’s offboarding process left a former employee’s external NPMJS publishing capability alive long enough for a phished session token / API credential to be weaponized.
- Downstream dApps had also accepted a fragile trust model: a browser-executed wallet-connection dependency could update from a runtime loader / CDN path and immediately change what transactions users were asked to sign.
- That makes Ledger a clean seam case between software supply-chain compromise, release-provenance failure, and third-party runtime allowance and integrity pinning: the compromise first lived upstream in Ledger’s shared package / loader ecosystem, but the sharper release-integrity follow-up is exactly
same real site, different loader-resolved bytes, and the sharper browser-policy follow-up is why real dApp domains were still willing to execute mutable remote wallet code at all. - The preserved invariant is
the wallet-connection layer served through the canonical dApp must not be mutable by an attacker into signer-draining approval or transfer prompts. Once that invariant failed, audited contracts downstream stopped mattering.
- Exploit path:
- The attacker phished a former Ledger employee and captured access to that employee’s still-valid NPMJS publishing session.
- They published malicious
@ledgerhq/connect-kitreleases1.1.5,1.1.6, and1.1.7. - DApps using Ledger’s dynamic loader path pulled the poisoned package from the distribution channel / CDN and served it under their legitimate domains.
- Users visited real dApps such as
hey.xyz,sushi.com,zapper.xyz, and others, but the browser now executed attacker-injected wallet code. - The malicious payload displayed fake or attacker-shaped wallet prompts, using a rogue WalletConnect project and Angel Drainer infrastructure to request approvals, permits, or direct draining calls depending on the assets it found.
- Victims signed because the surrounding site, URL, and app flow were genuine.
- The operator wallet then executed the drainer’s privileged
multicallmachinery, routing roughly85%of stolen value to the collector wallet and15%to the Angel Drainer fee collector. - Ledger pushed clean version
1.1.8, coordinated with WalletConnect to disable the rogue project, and relied on CDN cache expiry plus partner mitigation before the malicious path fully disappeared.
- What the attacker needed to be true:
- A still-authorized external publishing account had to remain reachable after employee offboarding.
- Downstream dApps had to trust a runtime-loaded shared dependency instead of a pinned, audited local artifact.
- Users had to keep trusting the canonical front end even though the wallet-connection layer beneath it had silently changed.
- Wallet UX had to make the malicious approval / permit / transfer requests plausible enough that at least some users would sign them before warnings spread.
- CDN propagation and cache retention had to keep the poisoned artifact available long enough for meaningful theft even after Ledger pushed a fix.
- Technical anatomy worth remembering:
- This incident broadened the Badger-style
real site, malicious wallet promptfamily into a supply-chain branch: the attacker did not own the downstream dApp domain itself; they owned a shared dependency that many dApps executed. - It also preserves a sharper browser-policy warning than Badger or Curve: the downstream dApps’ own registrar, DNS, and CDN stacks did not have to fail first. Their real domains still delegated signer-critical execution to Ledger’s mutable loader / CDN path, so domain authenticity only proved the surrounding page shell and bootstrap choice, not the wallet-construction bytes users actually ran.
- That keeps Ledger mechanically between software supply-chain compromise, third-party runtime allowance and integrity pinning, canonical-domain runtime-byte integrity, and release-provenance failure: upstream package publication was the first compromise, but each downstream app also kept a signer-critical route willing to execute remote shared code instead of a pinned local artifact. Inside the broader supply-chain family, Ledger is the clean
same real site, different loader-resolved bytescousin; Polyfill is the adjacentsame familiar runtime URL, different operator-resolved bytescousin; Badger and Curve are theone protocol's own delivery stack broke firstcousins. - Ledger said versions
1.1.5-1.1.7were malicious, with the exploit using a rogue WalletConnect project to reroute assets. - Sonatype observed that version
1.1.7embedded a drainer directly, while1.1.5and1.1.6pulled a secondary malicious package. - Blockaid tied the campaign to Angel Drainer infrastructure, including a main draining contract with an owner-only
multicallbackdoor and a visible85%/15%revenue split between operator collection and drainer-service fees. - Ledger estimated the poisoned file remained publicly retrievable for about five hours because of CDN caching, but the active draining window was under two hours.
- The attack affected any wallet using the compromised dApps, not only Ledger hardware-wallet users.
- This incident broadened the Badger-style
- Representative transactions and addresses:
- Main drainer contract:
0x000067464bdcbec51051ddcce8551e702f130000 - Collector wallet:
0x658729879fca881d9526480b82ae00efc54b5c2d - Operator wallet / drainer owner:
0x00003ffA7857408ab714c28B1451914330240000 - Angel Drainer fee collector:
0x412f10AAd96fD78da6736387e2C84931Ac20313f - Example drainer transaction highlighted by Blockaid:
0x730884cebcb36e272387b39cf75ed529ec2c1586b8b53955323e6dd51a9f70dd - Tether freeze transaction cited by Ledger:
0xf2b76233561ded9382612352eb4cd511e081b715b577c2e2236704af9e8050f4
- Main drainer contract:
- Response / mitigation:
- Ledger released clean package version
1.1.8within about 40 minutes of becoming aware of the attack. - WalletConnect disabled the rogue project used by the malicious payload.
- Tether froze the attacker’s USDT onchain during the same-day response.
- Affected dApps shut down front ends, pinned or replaced package versions, and warned users not to interact until caches had cleared and safe artifacts were confirmed.
- The still-important recovery question was not only
was 1.1.8 published?butwhat exact bytes were users still fetching through the loader / CDN path, from which caches, and with which WalletConnect/runtime identifiers still embedded. In the exact-production-artifact language, Ledger is the cleansame real site, different loader-resolved bytesrollback problem: recovery was not honest until operators could prove that the real downstream domains had stopped resolving the poisoned loader-selected artifact everywhere users actually hit them. This is the cleanest wallet-drainer exemplar for exact production artifact attestation and rollback discipline. - Ledger said it would tighten offboarding controls for external tools, reinforce deployment and code-signing controls, and expand monitoring around package publication and distribution.
- Ledger released clean package version
Pattern tags
- software-supply-chain-compromise
- release-provenance-failure
- Same real dApp, different loader-resolved bytes: downstream sites stayed canonical while Ledger’s runtime loader / CDN path quietly changed the wallet-connection code executed in user browsers
- Offboarded external publisher access quietly outranked code-review assumptions: a former employee’s still-live NPMJS publishing session was enough to mutate signer-facing production bytes across many unrelated dApps at once
- Runtime rollback lag mattered as much as initial compromise:
1.1.8release was not full recovery until CDN caches, WalletConnect routing, and downstream loader paths stopped resolving the malicious artifact everywhere users still hit it
Three release-and-wallet-authority promotions this incident collapsed
-
A real shared publication and loader path existed
- Ledger’s former employee still had live NPMJS publication reach, and downstream dApps had already chosen a real
connect-kit-loaderpath that fetched signer-facing code at runtime from Ledger’s distribution channel. - This is only the reachability fact: an authentic ecosystem-wide route still existed for publishing and resolving wallet middleware bytes.
- Ledger’s former employee still had live NPMJS publication reach, and downstream dApps had already chosen a real
-
That route still counted as canonical signer-facing runtime truth for real dApps
- Once the malicious
1.1.5-1.1.7packages landed, genuine downstream domains still loaded those bytes as if they were the ordinary Ledger Connect Kit users meant to run. - This is the runtime-authenticity promotion:
loaded from the expected Ledger path under the expected dApp domainsilently becamethis is still the correct wallet-connection code for this session.
- Once the malicious
-
That accepted runtime still inherited live wallet authority
- The poisoned runtime could now ask for approvals, permits, fake claims, or direct transfers and rely on real users to sign them inside genuine dApp sessions.
- This is the economic authority promotion: accepted signer-facing runtime drift still retained the power to convert user trust into spendable onchain authority.
Why the exploit worked
- Ledger Connect Kit’s runtime-loader model let one compromised publication path fan out instantly across many legitimate dApps. Those sites did not need to be breached individually because they had already delegated signer-critical execution to Ledger’s mutable distribution channel.
- The offboarding miss was decisive. Ledger’s own report says the former employee had lost internal access but still retained NPMJS publication rights, so one phished external session token sat close enough to production to become package-distribution authority.
- Real downstream domains were not enough to save users. Canonical dApp branding and URLs stayed intact while the wallet-connection bytes under those pages changed underneath them, which made malicious prompts look like ordinary wallet flows.
- The Angel Drainer payload did not need one single drain path. It could choose approvals, permits, fake claims, or direct transfers depending on the victim’s asset mix, which raised conversion from
poisoned dependencyintosigned theft. - Recovery also had an execution-layer lag: even after Ledger pushed
1.1.8and WalletConnect disabled the rogue project, CDN caching meant some users could still fetch the bad artifact for longer than the publication window itself.
Detection and audit pivots
- Inventory every signer-critical external publish and distribution surface — NPM org ownership, API keys, session tokens, CDN invalidation paths, runtime loaders, WalletConnect project identifiers, and any offboarding steps that still require manual cleanup.
- Compare the reviewed local artifact against the exact loader-resolved bytes browsers execute in production. If a dApp cannot say which Connect Kit bytes and which remote identifiers a user fetched at a given time, its rollback story is incomplete.
- Alert on unusual wallet-connection drift at the ecosystem layer: new spender prompts, new permit domains, unfamiliar WalletConnect project IDs, or a sudden cross-dApp cluster of similar approval requests.
- Rehearse emergency rollback under cache reality, not only package-registry reality. A clean package publish is not enough if CDN edges, browser caches, or embedded loader paths can still resolve the old malicious artifact.
- Ask whether the dApp truly needs mutable remote wallet code at all. Pinning, self-hosting, artifact attestation, and strict runtime-allowance policy are design questions here, not optional frontend hygiene.
Failure-prevention checklist
- Remove departing staff from external publish surfaces with the same rigor as internal repositories and production consoles. NPM org membership, automation tokens, package-owner roles, CDN publish rights, and package-loader configuration must all be part of the offboarding truth set rather than a manual afterthought.
- Require stronger publication ceremony for signer-critical packages: short-lived credentials, hardware-backed auth where available, dual control for releases, publish provenance, and alerts on new versions or ownership changes before downstream loaders ingest them.
- Prefer pinned, self-hosted, or explicitly versioned wallet-connection artifacts over mutable runtime loaders on signer-facing routes. If dynamic loading is unavoidable, constrain it with exact-version allowlists, integrity checks, and fast kill switches.
- Treat remote identifiers as production security state. WalletConnect project IDs, CDN URLs, package versions, and loader manifests should be inventory-controlled and rollback-tested just like contract addresses or proxy admins.
- Build rollback around the artifact users actually fetch, not only the registry state. CDN cache purge, browser-cache invalidation guidance, and downstream dApp confirmation of the resolved bytes should already be rehearsed before an incident.
- Monitor cross-app approval and permit telemetry for ecosystem-wide drift. A shared wallet library compromise usually shows up first as many real domains suddenly presenting one unfamiliar spender, permit target, or signing pattern.
- Keep signer-facing runtimes small and boring. The less mutable remote code sits on the wallet-connect path, the less one compromised package can redefine user intent across the ecosystem.
- Preserve user-side blast-radius controls too: exact approvals, permit scope limits, human-readable signing, and route-local pauses should all assume that one signer-critical dependency may eventually betray its brand.
Audit prompts
- Which external accounts can publish, promote, mirror, or serve signer-critical wallet code today, and which of those rights still depend on manual offboarding or token cleanup?
- If the reviewed source tree is honest, what exact mechanism proves that the bytes a user fetched from the runtime loader / CDN still correspond to that reviewed artifact and version?
- Can a dApp operator name the exact Connect Kit version, remote script URL, WalletConnect project ID, and integrity metadata a specific user session consumed during a specific time window?
- What prevents one compromised SDK or loader release from fanning out to every production dApp at once: version pinning, staged rollout rings, integrity pinning, allowlisted remote URLs, or nothing but trust in the package publisher?
- How quickly can operators revoke or disable a malicious remote artifact across package registry, CDN edge, cached loader manifests, and downstream app configuration simultaneously?
- Which alerts would fire first if a shared wallet library started draining users right now: unusual package publication, changed remote byte hashes, new signer prompt patterns, unfamiliar permit domains, or only after funds begin moving?
- Are downstream apps actually able to run in a degraded safe mode with wallet connection disabled or pinned locally, or does their dependency model force them to choose between full exposure and total outage?
- Which user-authority limits still matter after the runtime is compromised: exact-amount approvals, permit expiry, wallet clear-signing, route-local freezes, or post-approval revoke campaigns?
Lessons that should already be standard
Real dApp domainis not enough when signer-critical code is selected at runtime from a mutable upstream loader. The browser shell can stay honest while the wallet prompt meaning changes underneath it.- Offboarding gaps on external tooling are production-security bugs. A former employee’s stale package-publish right can be as dangerous as a leaked proxy-admin key when the package defines wallet behavior.
- Published fix is not the same thing as recovered production. In signer-facing supply-chain incidents, rollback is only real once the exact bytes users fetch from every cache and edge are known-good again.
- Shared wallet middleware is custody infrastructure in practice. If one package can change what many real apps ask users to sign, that package deserves treasury-grade release and monitoring discipline.
- Ecosystem-wide approval drift is an early-warning signal. The first reliable symptom may be many legitimate apps suddenly requesting the same strange approval or permit, not one protocol reporting a contract exploit.
- Dynamic convenience on wallet-connect paths should be treated as borrowed risk, not free UX.
Always pull the latest versionis another way of sayingallow upstream publication events to redefine signer intent in production. - A clean source repository or uncompromised downstream app does not rescue users if the executed artifact drifted elsewhere in the release chain.
- Recovery plans for signer-path supply-chain events must assume cache physics, third-party identifiers, and user-granted approvals outlive the initial publication mistake.
Why this incident matters
- It is one of the cleanest preserved examples of a wallet-drain incident where the decisive control surface lived in shared front-end dependency distribution rather than in the downstream protocols’ contracts.
- It demonstrates that
connect walletmiddleware is effectively custody infrastructure whenever it can change what a real dApp asks users to sign. - It also shows why
real domainis not a complete security boundary: dozens of uncompromised dApps can simultaneously become malicious if they inherit a poisoned dependency at runtime.
Internal linkages
- Core recurring pattern: software-supply-chain-compromise.
- Narrower browser-policy companion: third-party-runtime-allowance-and-integrity-pinning — Ledger is also a clean case where real dApp domains still allowed signer-critical pages to execute mutable remote loader code from outside the app’s own reviewed artifact.
- Broader browser-delivery companion: canonical-domain-runtime-byte-integrity — the affected dApps’ real domains remained genuine, but that domain-level authenticity was not enough to prove safe wallet runtime bytes once execution was delegated to Ledger’s loader / CDN path.
- Sharper artifact-drift family: release-provenance-failure.
- Positive-design recovery companion: exact-production-artifact-attestation-and-rollback-discipline — the rollback side of the same
same real site, different loader-resolved bytesproblem. - Parent / adjacent family: frontend-compromise-approval-phishing — Ledger is the
shared dependency compromised firstbranch of the broaderreal site, malicious promptfamily. - Adjacent pattern: arbitrary-call-token-approval-drain — both end in token theft via user-granted authority, but Ledger Connect Kit captured that authority through a poisoned shared interface dependency rather than through one protocol’s buggy router.
Control surface
-
The real leverage sat in package-publishing authority, CDN/runtime distribution, wallet-connection middleware, and the exact signing prompts shown by canonical dApps.
-
Once the shared wallet-connect layer was mutable by an attacker, dozens of downstream domains inherited the same wallet-drain path without any onchain upgrade or contract exploit.
-
Sources:
- https://www.ledger.com/blog/security-incident-report
- https://www.blockaid.io/blog/attack-report-ledger-connect-kit
- https://slowmist.medium.com/supply-chain-attack-on-ledger-connect-kit-analyzing-the-impact-and-preventive-measures-1005e39422fd
- https://www.sonatype.com/blog/decrypting-the-ledger-connect-kit-compromise-a-deep-dive-into-the-crypto-drainer-attack
- https://www.bleepingcomputer.com/news/security/ledger-dapp-supply-chain-attack-steals-600k-from-crypto-wallets/
-
Last reviewed: 2026-08-04 UTC