Conversation
## Because - A device could send a command name of `__proto__`, `constructor` or `prototype`. The `availableCommands` map used that name as a key. - The map came from an object literal, so those keys reached `Object.prototype`. ## This pull request - Builds the aggregated map with `Object.create(null)` in `transformers.ts`, and skips rows with a blocked name. - Adds a negative lookahead to `DEVICE_COMMAND_NAME` in `validators.js` that rejects the three exact names. The character class and the 1-100 length stay the same. No URI prefix is necessary. - Uses `Object.hasOwn` in the `invoke_command` handler, because a null prototype map has no inherited `hasOwnProperty`. - Updates the documented regex in `auth-server-api.ts` to match. - Adds a mocha spec for the aggregation, and jest cases for the regex and the `availableCommands` schema. The `invoke_command` fixture now uses a null prototype map, so a return to `.hasOwnProperty()` fails the suite. ## Issue that this pull request solves Closes: https://mozilla-hub.atlassian.net/browse/FXA-13270
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The implementation appears sound and tested, but this security-sensitive authentication and persistence path warrants final human review.
Pull request overview
Hardens device-command handling against prototype-polluting names.
Changes:
- Validates and filters unsafe command names.
- Uses null-prototype maps and
Object.hasOwn. - Adds focused validation, aggregation, and route tests.
File summaries
| File | Description |
|---|---|
packages/fxa-shared/test/db/transformers.ts |
Tests secure aggregation behavior. |
packages/fxa-shared/db/transformers.ts |
Builds safe maps and filters blocked keys. |
packages/fxa-auth-server/lib/routes/validators.spec.ts |
Tests command-name regex. |
packages/fxa-auth-server/lib/routes/validators.js |
Rejects unsafe exact names. |
packages/fxa-auth-server/lib/routes/devices-and-sessions.spec.ts |
Exercises null-prototype command maps. |
packages/fxa-auth-server/lib/routes/devices-and-sessions.js |
Safely checks command ownership. |
packages/fxa-auth-server/lib/devices.spec.ts |
Tests schema filtering behavior. |
packages/fxa-auth-server/docs/swagger/auth-server-api.ts |
Documents the revised regex. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Because
__proto__,constructororprototype. TheavailableCommandsmap used that name as a key.Object.prototype.This pull request
Object.create(null)intransformers.ts, and skips rows with a blocked name.DEVICE_COMMAND_NAMEinvalidators.jsthat rejects the three exact names. The character class and the 1-100 length stay the same. No URI prefix is necessary.Object.hasOwnin theinvoke_commandhandler, because a null prototype map has no inheritedhasOwnProperty.auth-server-api.tsto match.availableCommandsschema. Theinvoke_commandfixture now uses a null prototype map, so a return to.hasOwnProperty()fails the suite.Issue that this pull request solves
Closes: https://mozilla-hub.atlassian.net/browse/FXA-13270
Checklist
Put an
xin the boxes that applyHow to review (Optional)
db/transformers.tsandlib/routes/validators.js.validators.js,transformers.ts,devices-and-sessions.js, then the tests.constructor2and a URI that ends in/prototypestill pass, which the tests cover.Screenshots (Optional)
Other information (Optional)
stripUnknown: true. A blocked command name drops out of the payload, and the request does not fail. Joi also drops an own__proto__key when it clones the object, so that name never raises a Joi error.jest --selectProjects unitin fxa-auth-server gives 3993 passed, 0 failed. The fxa-shared mocha unit run gives 570 passing, and the jest unit run gives 18 passed.eslintexits 0 for both packages, andtsc -p packages/fxa-shared/tsconfig.json --noEmitexits 0.nx linttarget could not run in this sandbox. It starts withglean-lint, which needs a Python venv from PyPI, and the sandbox has no route to PyPI. CI covers it.