#38003 [BC-Medium] A malicious coordinator calling `Emily::update_deposits` can make the entire Sign
Description
Brief/Intro
Vulnerability Details
#[instrument(skip(context))]
pub async fn update_deposits(
context: EmilyContext,
body: UpdateDepositsRequestBody,
) -> impl warp::reply::Reply {
debug!("In update deposits");
// Internal handler so `?` can be used correctly while still returning a reply.
async fn handler(
context: EmilyContext,
body: UpdateDepositsRequestBody,
) -> Result<impl warp::reply::Reply, Error> {
// Get the api state and error if the api state is claimed by a reorg.
//
// Note: This may not be necessary due to the implied order of events
// that the API can receive from stacks nodes, but it's being added here
// in order to enforce added stability to the API during a reorg.
let api_state = accessors::get_api_state(&context).await?;
api_state.error_if_reorganizing()?;
// Validate request.
let validated_request: ValidatedUpdateDepositsRequest = body.try_into()?;
// Infer the new chainstates that would come from these deposit updates and then
// attempt to update the chainstates.
let inferred_chainstates = validated_request.inferred_chainstates()?;
for chainstate in inferred_chainstates {
// TODO(TBD): Determine what happens if this occurs in multiple lambda
// instances at once.
crate::api::handlers::chainstate::add_chainstate_entry_or_reorg(&context, &chainstate)
.await?;
}
// Create aggregator.
let mut updated_deposits: Vec<(usize, Deposit)> =
Vec::with_capacity(validated_request.deposits.len());
// Loop through all updates and execute.
for (index, update) in validated_request.deposits {
let updated_deposit =
accessors::pull_and_update_deposit_with_retry(&context, update, 15).await?;
updated_deposits.push((index, updated_deposit.try_into()?));
}
updated_deposits.sort_by_key(|(index, _)| *index);
let deposits = updated_deposits
.into_iter()
.map(|(_, deposit)| deposit)
.collect();
let response = UpdateDepositsResponse { deposits };
Ok(with_status(json(&response), StatusCode::CREATED))
}
// Handle and respond.
handler(context, body)
.await
.map_or_else(Reply::into_response, Reply::into_response)
}Impact Details
Fix
References
Proof of Concept
Previous#37545 [BC-Medium] Deposits with a lock_time of 16 cannot be processedNext#37479 [BC-High] A single signer can lock users' funds by not notifying other signers of the execute
Last updated
Was this helpful?