Any/all of authenticators skip postexecution checks
Description
The Authenticator
interface implements a ConfirmExecution
handler, which is executed by the post-handler. This can be used to enforce transaction rules or validate any posttransaction changes. The ConfirmExecution
handler can reject a transaction if any rules are violated.
The AllOfAuthenticator
and AnyOfAuthenticator
authenticators allow use of multiple authenticators at once. Ideally, it should invoke the ConfirmExecution
handler for all SubAuthenticators
.
func (aoa AllOfAuthenticator) ConfirmExecution(ctx sdk.Context, account sdk.AccAddress, msg sdk.Msg, authenticationData iface.AuthenticatorData) iface.ConfirmationResult {
for _, auth := range aoa.executedAuths {
if confirmation := auth.ConfirmExecution(ctx, nil, msg, authenticationData); confirmation.IsBlock() {
return confirmation
}
}
return iface.Confirm()
}
The ConfirmExecution
handler for these authenticators iterate over executedAuths
and invoke ConfirmExecution
for the SubAuthenticators
. However, executedAuths
is never actually set anywhere.
Impact
The ConfirmExecution
handlers for the SubAuthenticators
are never invoked. Therefore, the postexecution checks are always skipped. This could allow an attacker to bypass any posttransaction checks and/or violate spending and transaction limits.
Recommendations
The ConfirmExecution
handler for the AllOfAuthenticator
and AnyOfAuthenticator
should always invoke the ConfirmExecution
handlers for all registered SubAuthenticators
.
Remediation
The issue was fixed in PR #6787↗ with removal of executedAuths
. However, the implementation was updated to allow ConfirmExecution
to succeed if the ConfirmExecution
handler for any of the SubAuthenticators
pass.
Upon Discussion with the team, this was reverted to the original implementation in PR #6838↗ and merged in commit d56de736↗. This now requires ConfirmExecution
handlers for all of the SubAuthenticators
to succeed.