Category: Coding Mistakes
Only the first signer is authenticated
High Severity
High Impact
High Likelihood
Description
The ante handler for the authenticator assumes that there can only be a single signer for any message:
for msgIndex, msg := range msgs {
// By default, the first signer is the account
account, err := utils.GetAccount(msg)
if err != nil {
return sdk.Context{}, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprintf("failed to get account for message %d", msgIndex))
}
[...]
authentication := authenticator.Authenticate(cacheCtx, account, msg, authData)
if authentication.IsRejected() {
return ctx, authentication.Error()
}
func GetAccount(msg sdk.Msg) (sdk.AccAddress, error) {
if len(msg.GetSigners()) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "no signers")
}
return msg.GetSigners()[0], nil
}
It only authenticates the first signer for a message. However, it is possible for a message to have multiple signers.
Impact
An attacker can skip authentication for a message requiring multiple signers. The attacker would only need to authenticate the first account for the message and skip authentication for the remaining accounts.
Recommendations
Every signer in the message should be authenticated, or support for messages with multiple signers should be removed.
Remediation
This issue has been acknowledged by Osmosis Labs, and a fix was implemented in commit eb2facfb↗. The authenticator now only allows messages with exactly one signer.