A Sovereign View of Drift Protocol’s Security Failure
Drift Victims Committee • April 5, 2026I. Executive Summary
On March 25, 2026, Drift performed what they described as a "planned multisig migration" for their core programs. During this process, 4 out of 5 existing multisig members were replaced.
A few days later, two compromised signing accounts from the new multisig were used to authorize two consecutive transactions. These transactions utilized two Durable Nonce accounts (both funded by the same unidentified wallet) to initiate an state update for the core Drift V2 program dRiftyHA...33UH with an interval of just over one second.
At that moment, Drift lost administrative control, and the funds were rapidly drained.
II. Governance Infrastructure: Implementation via Squads V4
Technical Note: The Squads Protocol - Solana Industrial standard - functioned as designed. The incident was not caused by its smart contract vulnerability - the protocol executed instructions according to the administrative parameters active at the time of the transaction.
Pre-Incident Configuration (April 2024)
The core program was governed by multisig 61ApQqLoWVfTuzua9c22SWMj78RGv77x6Z2kzcJVGNjP. Its initial parameters were:
| Parameter | Value |
|---|---|
| Multisig Account | 61ApQqLoWVfTuzua9c22SWMj78RGv77x6Z2kzcJVGNjP |
| Config Authority | DuLz9HZxh1DeupPveJZfrJXKN43yXZs8Api4fhDf9YZ6 |
| Threshold | 3 / 5 |
| Timelock | 0 seconds |
| --- | |
| Member 1 | BW9BDDXug3btfGHydLi6R78VJJB2xNrd3Qvve1vj3sjx |
| Member 2 | MK6bTjdEsvrBGjbm4s2UmeBKL6yRp1UeiUoXKyAzgf2 |
| Member 3 | 39JyWrdbVdRqjzw9yyEjxNtTbTKcTPLdtdCgbz7C7Aq8 |
| Member 4 | 45cZ5Fj97Va5Abipr6NN8Zf1BqZqWneSek1hU5cQRvhw |
| Member 5 | 6WU7WGYywMENMQRabQVbmTKMFNuXGYQ3WNVmLnVHnEVy |
Multisig creation tx: 3tWYwWA...7dXeh
The March 25, 2026 (Migration)
The new multisig was created with parameters:
| Parameter | Value |
|---|---|
| Multisig Account | 2LW6PSEjp81xSEttWwXDB6Etb1eKdhYPbFEojYbyhx88 |
| Config Authority | A1eC8n2tQBHPodn8sZHsc5XWciunZy9B1VgmcHgK1xhP |
| Threshold | 2 / 5 |
| Timelock | 0 seconds |
| --- | |
| Member 1 | 39JyWrdbVdRqjzw9yyEjxNtTbTKcTPLdtdCgbz7C7Aq8 |
| Member 2 (new) | 6UJbu9ut5VAsFYQFgPEa5xPfoyF5bB5oi4EknFPvu924 |
| Member 3 (new) | 7TxYEAKSHRuCs1QpxssoeuaewqdQzHf93EKQP7bNYYxh |
| Member 4 (new) | 13GXtbGV8mNfNLDNbVKPrTcHTpfZ4CYrXviRCZmyxQvj |
| Member 5 (new) | HgjySRE1j9T2NwFrGbK2hXk4Przoz31xdciedmt6CHF6 |
New Multisig creation tx: 3aKRMvoc6JR...F8xoQrr
Drift retained one old signer, added four new ones, while using threshold = 2 and still ignoring the timelock.
But can we be sure that the current level of protection is exactly 2/5?
III. The "Controlled Multisig"
In Squads V4, the Config Authority is a privilege parameter. When set, the multisig becomes Controlled. This means a single account - the Config Authority - can unilaterally add/remove members or change threshold/timelock without a quorum.
As per the Squads Documentation:
#[account]
pub struct Multisig {
/// Key that is used to seed the multisig PDA.
pub create_key: Pubkey,
/// The authority that can change the multisig config.
/// This is a very important parameter as this authority can change the members and threshold.
///
/// The convention is to set this to `Pubkey::default()`.
/// In this case, the multisig becomes autonomous, so every config change goes through
/// the normal process of voting by the members.
///
/// However, if this parameter is set to any other key, all the config changes for this multisig
/// will need to be signed by the `config_authority`. We call such a multisig a "controlled multisig".
pub config_authority: Pubkey,
/// Threshold for signatures.
pub threshold: u16,
/// How many seconds must pass between transaction voting settlement and execution.
pub time_lock: u32,
/// Last transaction index. 0 means no transactions have been created.
pub transaction_index: u64,
/// Last stale transaction index. All transactions up until this index are stale.
/// This index is updated when multisig config (members/threshold/time_lock) changes.
pub stale_transaction_index: u64,
/// Reserved for future use.
pub _reserved: u8,
/// Bump for the multisig PDA seed.
pub bump: u8,
/// Members of the multisig.
pub members: Vec<Member>,
}You can also explore the source code of Squads V4 and instructions here
Historical Use of Config Authority
On April 29, 2024, the Config Authority of Initial 61ApQqLoW...GNjP multisig acting as a sole signer lowered the threshold from 3/5 to 2/5
Transaction nRPgTEG1Vr...K5AiBR payload:
{
"args": {
"type": {
"defined": "MultisigChangeThresholdArgs"
},
"data": {
"newThreshold": {
"type": "u16",
"data": "2"
},
"memo": {
"type": {
"option": "string"
},
"data": null
}
}
}
}The migration on March 25, 2026, maintained this structure, setting the Config Authority to A1eC8n2tQBHPodn8sZHsc5XWciunZy9B1VgmcHgK1xhP. This is a standard plain-wallet, not a multisig, which holds the power over the protocol's governance settings.
IV. Operational Chaos: The Failure to React
On the day of the exploit, four specific transactions were attempted in a three-minute panic window:
These transactions attempted to remove compromised signers (6UJbu9... and 39JyWr...) via standard proposals:
{
"args": {
"type": {
"defined": "ConfigTransactionCreateArgs"
},
"data": {
"actions": {
"type": {
"vec": {
"defined": "ConfigAction"
}
},
"data": [
{
"removeMember": {
"oldMember": "6UJbu9ut5VAsFYQFgPEa5xPfoyF5bB5oi4EknFPvu924"
}
}
]
},
"memo": {
"type": {
"option": "string"
},
"data": null
}
}
}
}{
"args": {
"type": {
"defined": "ConfigTransactionCreateArgs"
},
"data": {
"actions": {
"type": {
"vec": {
"defined": "ConfigAction"
}
},
"data": [
{
"removeMember": {
"oldMember": "39JyWrdbVdRqjzw9yyEjxNtTbTKcTPLdtdCgbz7C7Aq8"
}
}
]
},
"memo": {
"type": {
"option": "string"
},
"data": null
}
}
}
}All four transactions failed with the error:
6020 | Instruction not supported for controlled multisig.
The initiators tried to use the standard multisig voting process. However, because this was a Controlled Multisig, the only valid method was a call from the Config Authority.
Once again, look at the Squads V4 source code:
This how it works with non-controlled multisig:
impl ConfigTransactionCreate<'_> {
fn validate(&self, args: &ConfigTransactionCreateArgs) -> Result<()> {
// multisig
require_keys_eq!(
self.multisig.config_authority,
Pubkey::default(),
MultisigError::NotSupportedForControlled
);
// ...
}And Controlled Multisig case (config_authority is set):
/// Remove a member/key from the multisig.
///
/// NOTE: This instruction must be called only by the `config_authority` if one is set (Controlled Multisig).
/// Uncontrolled Mustisigs should use `config_transaction_create` instead.
#[access_control(ctx.accounts.validate())]
pub fn multisig_remove_member(
ctx: Context<Self>,
args: MultisigRemoveMemberArgs,
) -> Result<()> {
let multisig = &mut ctx.accounts.multisig;
require!(multisig.members.len() > 1, MultisigError::RemoveLastMember);
multisig.remove_member(args.old_member)?;
multisig.invalidate_prior_transactions();
multisig.invariant()?;
Ok(())
}This suggests a staggering disconnect: the team (or those attempting to mitigate) did not completely understand their own security architecture or lacked access to the Config Authority key when it was needed most.
V. Post-Incident Recovery
Control was eventually regained by changing the Upgrade Authority of the program to a new multisig (E44y4G...) on April 2, 2026.
Current Multisig:
| Parameter | Value |
|---|---|
| Multisig Account | E44y4Gm693AFdGXk4zir5D3ivHn7jns9aWkm8c5q1NDQ |
| Config Authority | A1eC8n2tQBHPodn8sZHsc5XWciunZy9B1VgmcHgK1xhP |
| Threshold | 3 / 5 |
| Timelock | 0 seconds |
| --- | |
| Member 1 (new) | 7TxYEAKSHRuCs1QpxssoeuaewqdQzHf93EKQP7bNYYxh |
| Member 2 | 13GXtbGV8mNfNLDNbVKPrTcHTpfZ4CYrXviRCZmyxQvj |
| Member 3 (new) | HgjySRE1j9T2NwFrGbK2hXk4Przoz31xdciedmt6CHF6 |
| Member 4 (new) | 8GyLXWePLLwVDzoPmt8peTWCxp2ypbz2SuZHWNAraF8Z |
| Member 5 (new) | HC6BxMvDLfefSZE16FRRktLHD7JVFLuLKvNRidGzH7iH |
Multisig creation tx: 4FqXwrC6J...SFSaEBq
Despite the catastrophic failure, the protocol maintains a zero-second timelock and continues to utilize a plain-wallet as the Config Authority.
VI. The Narrative vs. On-Chain Reality
In the wake of the incident, a coordinated narrative emerged across social media and official channels, characterizing the event as a "highly sophisticated exploit" or a "state-sponsored cyber-attack" involving advanced social engineering.
However, the on-chain evidence tells a simpler story - the "sophistication" myth - an attack does not need to be "highly sophisticated" when the target’s security threshold is manually lowered to 2-of-5 and a single wallet acts as the ultimate authority.