-
Type:
Task
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Integration
-
200
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Summary
Add a client-type-aware validate() entrypoint to the Extensions API so an extension can reject
its own internal-only fields when supplied by an external client (field-level analog of the existing
stage-level get_client_type).
Background
CVE-261 (SERVER-126247) hardened native
$search/$searchMeta parsing to reject router-only internal fields (mongotQuery,
mergingPipeline, metadataMergeProtocolVersion, requiresSearchSequenceToken,
requiresSearchMetaCursor, limit, sortSpec, mongotDocsRequested, docsNeededBounds,
view) when supplied by an external client. The check lives in
LiteParsedSearchStage::validate() -> search_helpers::validateInternalSearchFieldsNotSetByUser()
(error 5491300).
In v9.0 the mongot extension provides $search/$searchMeta. On the extension path the stage
is lite-parsed as DocumentSourceExtensionOptimizable::LiteParsedExpandable, whose validate()
is the inherited no-op — so the native 5491300 rejection never runs.
Current safety (verified for 9.0)
Instrumented investigation confirmed the extension carries the user-supplied internal field
verbatim into $extensionSearch as the opaque mongot query — it is _not split out into a
mongos-side merging pipeline. mongot then rejects the malformed query
(Query should contain either an operator ...) and planShardedSearch aborts. The user's
mergingPipeline therefore never executes on mongos with router privileges, so the CVE-261
mechanism does not reproduce on the extension path.
This is safe but fragile: safety depends on the extension treating internal fields as inert query
content rather than routing directives. There is no enforced trust boundary on the extension path.
Desired robust fix
Mirror the existing stage-level client-type mechanism at the field level, owned by the extension
(no search-specific code in the host):
- Stage-level today: AggStageDescriptor::get_client_type() (C-API api.h) ->
AllowedWithClientType -> generic host enforcement (5491300). Fail-closed (defaults to
internal). - Field-level needed: a generic Extensions-API entrypoint that receives the client type (internal vs
external) so the extension can reject its own internal-only fields. The mongot extension owns the
field list and the rejection; the host stays generic.
Sketch
- C-API (src/mongo/db/extension/public/api.h): add a validate vtable fn on the parse node
(or descriptor) taking a MongoExtensionClientType. Add at the END of the struct; bump the API
minor version. Provide a fail-closed default. - Host (document_source_extension_optimizable.cpp): in LiteParsedExpandable::validate(opCtx)
compute isInternalClient(opCtx) and call the new generic _parseNode->validate(clientType).
No hasExtensionSearchStage(), no search_helpers:: call — this also lets the existing
search-specific TODO SERVER-121094 hooks be removed rather than multiplied. - SDK: add the SDK virtual with a safe default (host_connector handle + adapters on both sides, per
the API-change checklist in src/mongo/db/extension/CLAUDE.md). - mongot extension (10gen/mongot-extension, Rust):
implement the field-level rejection of its internal-only fields against its Rust SDK. Note that this will need to be a separate CLOUDP related ticket.
Related / tracking
| Ticket | Relevance |
|---|---|
| SERVER-126247 | Original CVE-261 fix (native path). |
| SERVER-114364 | "Support internal-only extension stages" (Closed/Fixed). Adds stage-level client-type metadata (get_client_type) so a whole extension stage can be rejected for external clients. Does not provide field-level validation, so it does not cover this need. |
| SPM-4488 | IDL-ify aggregation stages so internal-only field validation is auto-generated (long-term; postmortem's preferred end state). This field-level validate() entrypoint could be folded in here. |
| SERVER-130885 | "Validate $lookup internal-only fields are not set by external clients" — analogous native-side follow-up from the CVE-261 audit (SERVER-128089). |
No existing ticket tracks the field-level, client-type-aware extension validate() entrypoint —
this is new work (sibling to SERVER-114364, or part of SPM-4488).
Interim (already done)
Test coverage is split by path:
- jstests/with_mongot/e2e/search_internal_fields_rejected_by_external_client.js — native path;
asserts 5491300. Excluded from the search-extension families. - jstests/with_mongot/e2e_search_extension/search_internal_fields_ignored_by_extension.js —
extension path; asserts the security invariant (injected internal fields never leak confidential
data / never take effect), including the valid-operator + injected-mergingPipeline no-leak case.
Runs only on the search-extension families.
- is related to
-
SERVER-126247 $search.mergingPipeline is not properly validated
-
- In Code Review
-
-
SERVER-130885 Validate $lookup internal-only fields are not set by external clients
-
- In Progress
-
-
SERVER-121094 Remove Feature Flag for SPM-4532
-
- Backlog
-
-
SERVER-114364 Support internal-only extension stages
-
- Closed
-