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

Narrow string allowlists in RestrictedControllerMessenger instances #4031

Merged
merged 8 commits into from
Mar 7, 2024

Conversation

MajorLift
Copy link
Contributor

@MajorLift MajorLift commented Mar 7, 2024

Motivation

Some controllers have their allowed actions or events types for their RestrictedControllerMessenger set to string. This compromises allowlist security by enabling these controllers to gain unrestricted access to any external action or event.

Explanation

  • Fixes all instances in core of string being used to define RestrictedControllerMessenger allowlists.

  • Includes follow-up fixes to fix: accounts controller events and actions #4021.

    • Fixes accounts-controller allowlists being included in controller actions and events unions.
    • Fixes accounts-controller allowlists being exported at package-level.

References

Changelog

@metamask/approval-controller

Fixed

  • BREAKING: Narrow ApprovalControllerMessenger generic arguments AllowedActions, AllowedEvents from string to never.

@metamask/keyring-controller

Fixed

  • BREAKING: Narrow KeyringControllerMessenger generic arguments AllowedActions, AllowedEvents from string to never.

@metamask/network-controller

Fixed

  • BREAKING: Narrow NetworkControllerMessenger generic arguments AllowedActions, AllowedEvents from string to never.

@metamask/permission-controller

Fixed

  • BREAKING: Fix SideEffectMessenger so that it's defined with a RestrictedControllerMessenger that has access to PermissionController allowed actions.
    • The messenger's Actions generic parameter is widened to include the PermissionController actions allowlist.
    • The messenger's AllowedActions generic parameter is narrowed from string to the PermissionController actions allowlist.

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate

@MajorLift MajorLift force-pushed the 240307-narrow-string-allowlists branch from f9451ee to 3ae1ebe Compare March 7, 2024 17:04
@MajorLift MajorLift marked this pull request as ready for review March 7, 2024 17:12
@MajorLift MajorLift requested review from a team as code owners March 7, 2024 17:12
@MajorLift MajorLift force-pushed the 240307-narrow-string-allowlists branch 3 times, most recently from 9896a15 to 9e156c0 Compare March 7, 2024 17:24
@MajorLift MajorLift force-pushed the 240307-narrow-string-allowlists branch from 9e156c0 to 53582b1 Compare March 7, 2024 17:44
@@ -91,8 +91,7 @@ export type AccountsControllerActions =
| AccountsControllerUpdateAccountsAction
| AccountsControllerGetAccountByAddressAction
| AccountsControllerGetSelectedAccountAction
| AccountsControllerGetAccountAction
| AllowedAccountsControllerActions;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want allowlists to be included in the controller actions/events unions.

  • This interferes with the type narrowing base-controller does to distinguish internal/external actions/events.
  • This exposes allowlists externally since actions/events unions are exported at the package-level. We generally want allowlists to be scoped to its controller.


export type AccountsControllerEvents =
| AccountsControllerChangeEvent
| AccountsControllerSelectedAccountChangeEvent
| AllowedAccountsControllerEvents;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +2 to +15
AccountsControllerState,
AccountsControllerGetStateAction,
AccountsControllerSetSelectedAccountAction,
AccountsControllerSetAccountNameAction,
AccountsControllerListAccountsAction,
AccountsControllerUpdateAccountsAction,
AccountsControllerGetSelectedAccountAction,
AccountsControllerGetAccountByAddressAction,
AccountsControllerGetAccountAction,
AccountsControllerActions,
AccountsControllerChangeEvent,
AccountsControllerSelectedAccountChangeEvent,
AccountsControllerEvents,
AccountsControllerMessenger,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • This is not a breaking change. The list includes all preexisting exports and excludes Allowed{Actions,Events}.
  • Allowed{Actions,Events} should be exported from the module so they're available for tests and other internal files, but they should not be exported at the package level.
  • We want to avoid wildcard exports in general: Forbid wildcard exports eslint-config#331

Mrtenz
Mrtenz previously approved these changes Mar 7, 2024
Gudahtt
Gudahtt previously approved these changes Mar 7, 2024
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One suggestion for the changelog, but the diff LGTM!

@MajorLift
Copy link
Contributor Author

MajorLift commented Mar 7, 2024

Failing transaction-controller tests introduced by #3827 are fixed by the following changes. Merging #4013 first should take care of this.

diff --git a/packages/transaction-controller/src/TransactionControllerIntegration.test.ts b/packages/transaction-controller/src/TransactionControllerIntegration.test.ts
index 72c91fa44..23bd723fa 100644
--- a/packages/transaction-controller/src/TransactionControllerIntegration.test.ts
+++ b/packages/transaction-controller/src/TransactionControllerIntegration.test.ts
@@ -114,7 +114,11 @@ const setupController = async (
   const unrestrictedMessenger: UnrestrictedControllerMessenger =
     new ControllerMessenger();
   const networkController = new NetworkController({
-    messenger: unrestrictedMessenger.getRestricted({
+    messenger: unrestrictedMessenger.getRestricted<
+      'NetworkController',
+      never,
+      never
+    >({
       name: 'NetworkController',
     }),
     trackMetaMetricsEvent: () => {
@@ -129,7 +133,11 @@ const setupController = async (
   assert(blockTracker, 'Provider must be available');
 
   const approvalController = new ApprovalController({
-    messenger: unrestrictedMessenger.getRestricted({
+    messenger: unrestrictedMessenger.getRestricted<
+      'ApprovalController',
+      never,
+      never
+    >({
       name: 'ApprovalController',
     }),
     showApprovalRequest: jest.fn(),

mcmire
mcmire previously approved these changes Mar 7, 2024
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

… when used with `unrestrictedMessenger` pattern

- TODO: open ticket for more fundamental fix for this in `getRestricted` and `RestrictedControllerMessenger`
@MajorLift MajorLift dismissed stale reviews from Mrtenz, Gudahtt, and mcmire via 38d5e88 March 7, 2024 21:57
@MajorLift
Copy link
Contributor Author

The unrestrictedControllerMessenger pattern newly introduced in the TransactionControllerIntegration tests seems to have exposed a flaw in the recent getRestricted fix (#4013).

Omitting the allowed{Actions,Events} options in getRestricted doesn't result in their types being inferred as never[]. Instead, these options are typed with the "unrestricted" action/event union.

A temporary fix applied here is to pass in empty arrays into allowed{Actions,Events}: 38d5e88

But getRestricted and/or RestrictedControllerMessenger will need to be fixed for a fundamental solution that lets us omit allowed{Actions,Events}. I'll create a ticket for this.

@MajorLift MajorLift merged commit 5e84432 into main Mar 7, 2024
139 of 140 checks passed
@MajorLift MajorLift deleted the 240307-narrow-string-allowlists branch March 7, 2024 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Narrow string allowlists in RestrictedControllerMessenger instances
4 participants