Skip to content

Fix prototype-polluting assignments #4041

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

Merged
merged 17 commits into from
Mar 21, 2024

Conversation

MajorLift
Copy link
Contributor

@MajorLift MajorLift commented Mar 11, 2024

Explanation

Fixes prototype-polluting assignments by validating that dynamic-string property keys do not evaluate to __proto__, constructor, or prototype at runtime.

Defines isSafeDynamicKey validator and PROTOTYPE_POLLUTION_BLOCKLIST constant in @metamask/controller-utils.

References

Changelog

N/A

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 240311-fix-prototype-polluting-assignments branch 3 times, most recently from 5bbc465 to 1dc4299 Compare March 11, 2024 14:36
@MajorLift MajorLift changed the title [name-controller] Fix prototype-polluting assignments Fix prototype-polluting assignments Mar 11, 2024
@MajorLift MajorLift self-assigned this Mar 11, 2024
@MajorLift MajorLift added bug Something isn't working team-wallet-framework labels Mar 11, 2024
@MajorLift MajorLift marked this pull request as ready for review March 11, 2024 14:50
@MajorLift MajorLift requested a review from a team as a code owner March 11, 2024 14:50
@naugtur
Copy link
Contributor

naugtur commented Mar 12, 2024

How does this relate to SES? If the polluiton is on intrinsic Object.prototype, lockdown would prevent it.
If not, can we harden the objects in question? __proto__ is not the only way to pollute an object.

@Gudahtt
Copy link
Member

Gudahtt commented Mar 12, 2024

This work was motivated by our new security scanner, which highlighted this problem. I don't think the prototype pollution problem addressed here affects applications using lockdown.

@MajorLift MajorLift requested a review from a team as a code owner March 13, 2024 00:40
@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch 2 times, most recently from 3cb8cda to 1a32941 Compare March 13, 2024 00:56
@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from 0e7115c to 0ba0b11 Compare March 13, 2024 16:09
@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from 0ba0b11 to a2a561a Compare March 13, 2024 19:41
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.

Adding a function to check whether a single property makes sense to address this vulnerability now. It could be a bit confusing out of context, but I left some comments as to how we could explain it better.

As a future change, though, what are your thoughts about baking the check into a new function that would take an object and a property name and either set the property if it's safe or else throw an error?

@@ -194,6 +195,7 @@ export class EnsController extends BaseController<
delete(chainId: Hex, ensName: string): boolean {
const normalizedEnsName = normalizeEnsName(ensName);
if (
!isSafeDynamicKey(chainId) ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add a test for this? Seems important to check.

Copy link
Contributor

@legobeat legobeat Mar 14, 2024

Choose a reason for hiding this comment

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

The type as well as the following code assumes that chainId is Hex, which if true implies that isSafeDynamicKey9chainId) would also be true.

Maybe adding a runtime-check that the chainId actually starts with 0x will do just as well here as well as in packages/address-book-controller/src/AddressBookController.ts?

A function like isSafeDynamicKey still could be useful for other cases where untrusted input string can't be assumed to be hex (indexing on method names anywhere?) but it seems like a simpler hex-prefix check will solve for all the cases covered in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's true that isValidHexAddress for address and isSafeChainId for chainId would be sufficient validation to fix the violations currently found by the scanner.

However, it seems worth it to implement more generalized blocklisting logic for this vulnerability (https://portswigger.net/web-security/prototype-pollution/preventing#sanitizing-property-keys), which will also directly placate the CodeQL scanner.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, we could definitely make more improvements that would ensure we can protect against this vulnerability more generally.

That seems unrelated to my comment, though. Should we add tests which attempt to call delete with __proto__, constructor, and prototype and verify that they don't do anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added tests for all three files here: a145237. Coverage is up to 100 for the three modules. I didn't test every string in the blocklist, but it seems like verifying that the validation works should be enough?

Copy link
Contributor

Choose a reason for hiding this comment

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

Testing that it essentially just gets called is fine. Do we need tests for the function itself, though?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah of course I'll add that right now.

@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from af98612 to a2a561a Compare March 14, 2024 16:35
@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from 3863c6a to a145237 Compare March 14, 2024 17:12
@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from 20887be to 4d634ea Compare March 14, 2024 20:22

This comment was marked as resolved.

@MajorLift
Copy link
Contributor Author

@SocketSecurity ignore npm/[email protected]

New maintainer is a member of the vscode team and maintainer of 96 npm packages, many of them under the @microsoft/ namespace.

@SocketSecurity ignore npm/@lavamoat/[email protected]

Internal package and maintainer.

mcmire
mcmire previously approved these changes Mar 20, 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!

@MajorLift MajorLift force-pushed the 240311-fix-prototype-polluting-assignments branch from e702cd4 to f6c3c47 Compare March 20, 2024 23:14
* @param key - The dynamic key to validate.
* @returns Whether the given dynamic key is safe to use.
*/
export function isSafeDynamicKey(key: string): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

Not intending to block this PR, but this seems like it could be useful for @metamask/utils.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not opposed to moving it down the line if it fits better there!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working team-wallet-framework
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[address-book-controller, ens-controller] Fix prototype-polluting delete operations [name-controller] Fix prototype-polluting assignments
6 participants