Repository navigation
A security release. It fixes two vulnerabilities: values bound into a query could change it (GHSA-wwfj-6qr7-h9hq), and a filter could reveal the one-time tokens of the accounts module and the password hash (GHSA-8m4q-p5xx-x835). Every deployment should upgrade, and first of all those that use the accounts module, aggregations with variables, GraphQL apps, or permission filters with variables.
Some requests that were accepted are now refused, or bound differently: read "Behaviour changes" below before you upgrade.
Values bound into a query stay values (GHSA-wwfj-6qr7-h9hq)
The query is written by the trusted side: the aggregation, the GraphQL mapping, the permission. What comes from the request is a value. Four places let a value change the query.
Query parameters bound as aggregation variables (#814). Since 9.9.0 ?status=A binds {"$var": "status"}, but only avars went through the operator check of aggregation-check-operators. Now a query parameter that a pipeline, or the notify_when of a change stream, reads with $var or $ifvar gets the same check: a value with an operator gets 400. A parameter the pipeline does not read is not checked.
Strings starting with $ (#815). A variable whose value is a string like "$name" or "$$ROOT" was read by MongoDB as a field path or a variable wherever the pipeline used it in an expression. With aggregation-check-operators enabled, the default, such a value is bound as {"$literal": value} in expressions. In a $match stage, outside $expr, it is left as it is: a query value.
GraphQL arguments (#816). The new option graphql.check-operators, true by default: an argument with operators is refused, and a string argument starting with $ is bound in $literal where MongoDB would read it as a field path or a variable. A mapping that lets the client write a query in an argument on purpose declares it:
{ "$ifarg": ["filter", { "$match": { "$arg": "filter", "operators": true } }] }The other arguments of the mapping keep the check. The find and sort of query mappings now go through the aggregationSecurity blacklists, as aggregation mappings already did.
Variables resolved by the server (#819). @request.body.<path> and @user.<property> are resolved by the server, but their values can come from the client. In a readFilter or a writeFilter a value with operators now matches no document, as an unbound variable does, and under $expr a string starting with $ is bound in $literal. In an aggregation it refuses the request with 400.
For plugin developers: VarResolver has the new method operatorsAllowed(), false by default. A resolver whose values are filters on purpose, as @mongoPermissions and @filter, returns true.
A filter cannot reveal the tokens of the accounts or the password hash (GHSA-8m4q-p5xx-x835)
A permission can hide a field with projectResponse, but a condition on that field, or a sort on it, still tells something about its value, request by request.
The one-time tokens of restheart-accounts (#817). The new interceptor denyFilterOnAccountTokens, enabled by default, refuses with 403, before the query runs, a request whose filter or sort refers to token in auth_invitations, or to emailVerificationToken, passwordResetToken or inviteToken in the users collection. With the token of a pending invitation or password reset a client could take over the account.
The password hash (#818). denyFilterOnUserPwd checked only keys in nested documents, and only on a GET. It now checks the whole filter, $or, $and, $nor and field paths in expressions included, and the sort and sort_by parameters. It applies to every method and runs before the request is executed, so a bulk PATCH or DELETE with a condition on the password is refused too.
9.16.0 already refuses ?filter, ?sort and ?sort_by on reads unless the permission sets mongo.allowFilter: true (#805). These two checks protect the deployments that allow them, and the bulk writes.
Behaviour changes
- A query parameter with an operator, read by a pipeline or a
notify_when, gets400. - A pipeline that let the client choose a field through a variable, e.g.
{"$group": {"_id": {"$var": "groupBy"}}}withgroupBy=$category, now gets the literal string. - In the query stages other than
$match($geoNear.query,$graphLookup.restrictSearchWithMatch,$search), a variable value with a string starting with$is refused by MongoDB. - A GraphQL app that receives MongoDB filters in a
BsonDocumentargument declares that argument with"operators": true.graphql.check-operators: falseturns the check off for every argument. - A request with a
filteror asorton a token of the accounts, or on the password, gets403on every method. - With
aggregation-check-operators: falseaggregation variables are bound as before.
Packages
- Maven Central:
org.restheart:restheart-*:9.17.0 - Docker:
softinstigate/restheart:9.17.0 - The zip, the tar.gz and the native binaries are attached to this release.