Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Policy_Type_group1 Can Activate flags.BlockHeaderVerificationFlags #533

Open
c4-bot-4 opened this issue Dec 18, 2023 · 8 comments
Open

Policy_Type_group1 Can Activate flags.BlockHeaderVerificationFlags #533

c4-bot-4 opened this issue Dec 18, 2023 · 8 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-a insufficient quality report This report is not of sufficient quality QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")

Comments

@c4-bot-4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/keeper/msg_server_update_crosschain_flags.go#L12-L58

Vulnerability details

Impact

ZetaChain implements a critical separation of privileges by using two types of Admin Groups. According to "Important Areas" documentation and the implementation itself, certain actions can only be executed by one group or the other.

  • Group1 is assigned for emergency actions that need rapidity over security, and is represented by an address that requires a single signature from its multisig scheme.

  • Group2 is assigned for operational actions influencing the logic of the blockchain that need security over rapidity, and is represented by an address that requires several signatures from its multisig scheme.

The issue is that Group1 is allowed to enable/disable the crosschain flag flags.BlockHeaderVerificationFlags. This not only differs from the "Important Areas" documentation, but is also a violation of the designed separation of privileges. More specifically, enabling the flags.BlockHeaderVerificationFlags cannot be justified as an emergency action and activates (instead of deactivating in case of emergency) critical operations in the blockchain. This renders a critical flag for the blockchain operation mistakenly open to only one address in the Group1 multisig.

Proof of Concept

This is the relevant (fixed) part of the "Permissions Table" in the "Important Areas" documentation:

Message Group Description Module
MsgUpdateCrosschainFlags - Disabling outbounds/inbounds 1 Disable inbound txs or outbound txs to be observed on ZetaChain observer
MsgUpdateCrosschainFlags - Other actions 2 Other actions for crosschain flags are: enabling disabled outbound/inbound, changing parameters for gas price increase mechanism observer

Admins in the Group1 should only be able to disable outbounds/inbounds for the case of emergencies, while all other actions should be reserved to Group2. But this is not what the code in the UpdateCrosschainFlags message function enforces:

func (k msgServer) UpdateCrosschainFlags(goCtx context.Context, msg *types.MsgUpdateCrosschainFlags) (*types.MsgUpdateCrosschainFlagsResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)

	requiredGroup := types.Policy_Type_group1
	if msg.IsInboundEnabled || msg.IsOutboundEnabled || msg.GasPriceIncreaseFlags != nil {
		requiredGroup = types.Policy_Type_group2
	}

	// check permission
	if msg.Creator != k.GetParams(ctx).GetAdminPolicyAccount(requiredGroup) {
		return &types.MsgUpdateCrosschainFlagsResponse{}, types.ErrNotAuthorizedPolicy
	}
    // ... SNIP...
	if msg.BlockHeaderVerificationFlags != nil {
		flags.BlockHeaderVerificationFlags = msg.BlockHeaderVerificationFlags
	}

	k.SetCrosschainFlags(ctx, flags)
    // ... SNIP ...

The flags.BlockHeaderVerificationFlags can be switched by both Group1 and Group2.

These flags are used in:

A simple unit test can be included in contest repository's file repos/node/x/observer/keeper/msg_server_update_crosschain_flags_test.go to test for the authorization flaw:

func TestMsgServer_UpdateBlockHeaderVerificationFlagsAUDIT(t *testing.T) {
	t.Run("Group1 can update BlockHeaderVerificationFlags", func(t *testing.T) {
		k, ctx := keepertest.ObserverKeeper(t)
		srv := keeper.NewMsgServerImpl(*k)
		admin := sample.AccAddress()

		setAdminCrossChainFlags(ctx, k, admin, types.Policy_Type_group1)

		// Group1 can change flags to `false`
		_, err := srv.UpdateCrosschainFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateCrosschainFlags{
			Creator: admin,
			BlockHeaderVerificationFlags: &types.BlockHeaderVerificationFlags{
				IsEthTypeChainEnabled: false,
				IsBtcTypeChainEnabled: false,
			},
		})

		require.NoError(t, err)
		flags, found := k.GetCrosschainFlags(ctx)
		require.True(t, found)
		require.False(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled)
		require.False(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled)

		// Group1 can change flags to `true`
		_, err = srv.UpdateCrosschainFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateCrosschainFlags{
			Creator: admin,
			BlockHeaderVerificationFlags: &types.BlockHeaderVerificationFlags{
				IsEthTypeChainEnabled: true,
				IsBtcTypeChainEnabled: true,
			},
		})

		require.NoError(t, err)
		flags, found = k.GetCrosschainFlags(ctx)
		require.True(t, found)
		require.True(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled)
		require.True(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled)
	})
}

Then run:

$ go test x/observer/keeper/msg_server_update_crosschain_flags_test.go -run TestMsgServer_UpdateBlockHeaderVerificationFlagsAUDIT

Tools Used

Manual: code editor.

Recommended Mitigation Steps

One potential solution that seems to adhere to the intended security model is to emulate what is done to the other critical flags and allow Group1 to only disable the flags.BlockHeaderVerificationFlags, for the cases of emergency situations. Or, if intended, just remove completely the Group1 permission to set flags.BlockHeaderVerificationFlags.

Assessed type

Access Control

@c4-bot-4 c4-bot-4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Dec 18, 2023
c4-bot-3 added a commit that referenced this issue Dec 18, 2023
@DadeKuma
Copy link

QA might be more appropriate

@c4-pre-sort
Copy link

DadeKuma marked the issue as insufficient quality report

@c4-pre-sort c4-pre-sort added the insufficient quality report This report is not of sufficient quality label Dec 20, 2023
@0xean
Copy link

0xean commented Jan 6, 2024

going to leave open for sponsor comment before downgrading.

@c4-sponsor
Copy link

lumtis (sponsor) confirmed

@c4-sponsor c4-sponsor added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label Jan 9, 2024
@lumtis
Copy link

lumtis commented Jan 9, 2024

Confirm validity. Need to be updated.

@0xean
Copy link

0xean commented Jan 10, 2024

while this is very well documented issue, I don't see how it is more than QA at this point.

It is essentially functionality not meeting the specification with little impact beyond that as both of these calls are privileged already.

@c4-judge
Copy link

0xean changed the severity to QA (Quality Assurance)

@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Jan 10, 2024
@c4-judge
Copy link

0xean marked the issue as grade-a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-a insufficient quality report This report is not of sufficient quality QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Projects
None yet
Development

No branches or pull requests

7 participants