Authz Module Non-Determinism
Description
The Cosmos-SDK is a framework for building blockchain applications in Golang. Affected versions of the SDK were vulnerable to a consensus halt due to non-deterministic behaviour in a ValidateBasic method in the x/authz module. The MsgGrant of the x/authz module contains a Grant field which includes a user-defined expiration time for when the authorization grant expires. In Grant.ValidateBasic(), that time is compared to the node’s local clock time. Any chain running an affected version of the SDK with the authz module enabled could be halted by anyone with the ability to send transactions on that chain. Recovery would require applying the patch and rolling back the latest block. Users are advised to update to version 0.44.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A non-deterministic time check in Cosmos SDK's x/authz module can cause a consensus halt; fixed in v0.44.2.
Vulnerability
The Cosmos SDK, versions 0.43.x and 0.44.0 through 0.44.1, contain a non-deterministic behavior in the x/authz module's ValidateBasic method. Specifically, the MsgGrant contains a Grant field with a user-defined expiration time. In Grant.ValidateBasic(), this expiration time is compared to the node's local clock time using time.Now().Unix(), which is subjective and non-deterministic across nodes. This vulnerability affects any blockchain network built with the affected SDK versions and with the authz module enabled [1][2][4].
Exploitation
An attacker with the ability to send transactions on the target chain can craft multiple MsgGrant messages with different but close expiration times (e.g., separated by a few seconds). By exercising the granted functionality for all of them near their expiration time, it becomes likely that some nodes consider grants expired while others do not, leading to a disagreement in state and a consensus halt. No special privileges beyond transaction submission are required [2][4].
Impact
Successful exploitation halts the blockchain's consensus, preventing further block production and transaction processing. Recovery requires applying the patch and rolling back the latest block, making this a high-severity availability impact [1][2].
Mitigation
The vulnerability is fixed in Cosmos SDK version 0.44.2, released on October 12, 2021. The fix removes the problematic time check entirely, as full validation of grant parameters occurs in the keepers. Users should upgrade to v0.44.2 or later. Network operators who cannot immediately upgrade should consider temporarily disabling the authz module. The vulnerability is not listed in CISA's Known Exploited Vulnerabilities catalog as of this writing [1][2][4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/cosmos/cosmos-sdkGo | >= 0.43.0, < 0.44.2 | 0.44.2 |
Affected products
3- Range: <0.44.2
- cosmos/cosmos-sdkv5Range: >= 0.43.0, < 0.44.2
Patches
168ab790a761eMerge pull request from GHSA-2p6r-37p9-89p2
5 files changed · +54 −10
x/authz/authorization_grant.go+5 −5 modified@@ -10,7 +10,11 @@ import ( ) // NewGrant returns new Grant -func NewGrant(a Authorization, expiration time.Time) (Grant, error) { +func NewGrant( /*blockTime time.Time, */ a Authorization, expiration time.Time) (Grant, error) { + // TODO: add this for 0.45 + // if !expiration.After(blockTime) { + // return Grant{}, sdkerrors.ErrInvalidRequest.Wrapf("expiration must be after the current block time (%v), got %v", blockTime.Format(time.RFC3339), expiration.Format(time.RFC3339)) + // } g := Grant{ Expiration: expiration, } @@ -51,10 +55,6 @@ func (g Grant) GetAuthorization() Authorization { } func (g Grant) ValidateBasic() error { - if g.Expiration.Unix() < time.Now().Unix() { - return sdkerrors.Wrap(ErrInvalidExpirationTime, "Time can't be in the past") - } - av := g.Authorization.GetCachedValue() a, ok := av.(Authorization) if !ok {
x/authz/authorization_grant_test.go+44 −0 added@@ -0,0 +1,44 @@ +package authz + +import ( + "testing" + "time" + + // banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" +) + +func expecError(r *require.Assertions, expected string, received error) { + if expected == "" { + r.NoError(received) + } else { + r.Error(received) + r.Contains(received.Error(), expected) + } +} + +func TestNewGrant(t *testing.T) { + // ba := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))) + a := NewGenericAuthorization("some-type") + var tcs = []struct { + title string + a Authorization + blockTime time.Time + expire time.Time + err string + }{ + // {"wrong expire time (1)", a, time.Unix(10, 0), time.Unix(8, 0), "expiration must be after"}, + // {"wrong expire time (2)", a, time.Unix(10, 0), time.Unix(10, 0), "expiration must be after"}, + {"good expire time (1)", a, time.Unix(10, 0), time.Unix(10, 1), ""}, + {"good expire time (2)", a, time.Unix(10, 0), time.Unix(11, 0), ""}, + } + + for _, tc := range tcs { + t.Run(tc.title, func(t *testing.T) { + // _, err := NewGrant(tc.blockTime, tc.a, tc.expire) + _, err := NewGrant(tc.a, tc.expire) + expecError(require.New(t), tc.err, err) + }) + } + +}
x/authz/client/testutil/tx.go+3 −3 modified@@ -127,11 +127,11 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() { "send", fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour), }, - 0, - true, + 0xd, + false, // TODO: enable in v0.45 }, { "fail with error invalid msg-type",
x/authz/keeper/msg_server.go+1 −1 modified@@ -10,7 +10,7 @@ import ( var _ authz.MsgServer = Keeper{} -// GrantAuthorization implements the MsgServer.Grant method. +// GrantAuthorization implements the MsgServer.Grant method to create a new grant. func (k Keeper) Grant(goCtx context.Context, msg *authz.MsgGrant) (*authz.MsgGrantResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) grantee, err := sdk.AccAddressFromBech32(msg.Grantee)
x/authz/msgs_test.go+1 −1 modified@@ -80,7 +80,7 @@ func TestMsgGrantAuthorization(t *testing.T) { {"nil granter and grantee address", nil, nil, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now(), false, false}, {"nil authorization", granter, grantee, nil, time.Now(), true, false}, {"valid test case", granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 1, 0), false, true}, - {"past time", granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 0, -1), false, false}, + {"past time", granter, grantee, &banktypes.SendAuthorization{SpendLimit: coinsPos}, time.Now().AddDate(0, 0, -1), false, true}, // TODO need 0.45 } for i, tc := range tests { msg, err := authz.NewMsgGrant(
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-2p6r-37p9-89p2ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-41135ghsaADVISORY
- forum.cosmos.network/t/cosmos-sdk-vulnerability-retrospective-security-advisory-jackfruit-october-12-2021/5349ghsax_refsource_MISCWEB
- github.com/cosmos/cosmos-sdk/commit/68ab790a761e80d3674f821794cf18ccbfed45eeghsax_refsource_MISCWEB
- github.com/cosmos/cosmos-sdk/releases/tag/v0.44.2ghsaWEB
- github.com/cosmos/cosmos-sdk/security/advisories/GHSA-2p6r-37p9-89p2ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.