Post-Mortem: 7/28/23: Forced Self-Delegation

This is a post-mortem document describing a medium severity [1] bug that was fixed on 7/28/23.


A vulnerability in the BondingManager contract used to manage the LPT stake of orchestrators and delegators was reported to the core team on 6/23/23 by a whitehat hacker, via Livepeer’s Immunefi bug bounty program. This vulnerability, if exploited, would have allowed an attacker to force a delegator to self-delegate and register as an orchestrator thereby preventing the delegator from delegating to an address of their choice. No funds were at risk of direct theft, but an exploit could have prevented delegators from delegating freely.



An attacker would have been able to grief a delegator by forcing a delegator address in the Unbonded state (i.e. has no delegated stake) to self-delegate (i.e. register as a transcoder) by calling bondForWithHint() with both _owner and _to set to the delegator’s address. The cost of the attacker’s transaction is 1 aLPT (1 LPT = 10^18 atto LPT = 10^18 aLPT), because that is the minimum amount of LPT that it needs to provide in order to execute the transaction, plus gas fees.

After the attacker’s transaction is executed, the delegator cannot change its delegation because registered orchestrators cannot change their delegation. The delegator can wait until the next round in order to fully unbond. At that point, if the delegator wishes to delegate to another address, it can call rebondFromUnbonded(), but if the attacker calls bondForWithHint() to force self-delegation before this then the rebondFromUnbonded() transaction will fail. The delegator is then only able to call rebond() to use its unbonding lock to delegate to itself or withdraw the unbonding lock amount once the unbonding period is over.

Potential Impact

The impact on a delegator every time this attack is executed is:

  • The delegator gains 1 aLPT
  • The delegator loses gas fees if its transaction fails because it was frontrun by the attacker’s transaction
  • The delegator is unable to delegate to another address for the duration of the round
  • The attacker loses 1 aLPT plus gas fees

This attack is repeatable so a delegator address could be consistently unable to delegate to another address as long as the attacker is willing to pay 1 aLPT (which is essentially transferred to the delegator) plus gas fees for each attack.

Likelihood of Exploitation

The primary motivation of the attacker would be to grief delegators by preventing them from delegating freely.

At the technical level, an attacker would need to selectively target addresses that want to delegate to another address by frontrunning all of the bond() transactions from addresses in the Unbonded state.

At the capital cost level, each attack would cost the attacker 1 aLPT plus gas fees.



The fix for the vulnerability was an additional conditional statement that ensured that a third party caller (i.e. not msg.sender and not the L2Migrator) cannot trigger self-delegation for an address that is in the Unbonded state.


The vulnerability could have been prevented with a more thorough review of the space of allowable actions for a third party caller made in the bondForWithHint() function and additional test cases for each of the allowable actions for the third party caller.

In the future, when introducing any new functionality that allows addresses to call functions on behalf of delegators/orchestrators all test cases will take into account the entire space of allowable actions for the third party caller ensuring that the third party caller has the required restricted privileges.


The core team thanks the Immunefi whitehat hacker for their responsible disclosure of this vulnerability which helped safeguard the users of the Livepeer network. They have been awarded a bug bounty payout for the disclosure based on the guidelines for reward amounts of medium vulnerabilities in the bug bounty program

[1] As classified based on the severity system used for the Immunifi bug bounty program.