Describe the bug
@tanstack/db is vulnerable to prototype pollution through public query APIs.
The root package entry exports queryOnce, createCollection, and localOnlyCollectionOptions. A caller can pass an alias containing prototype-pollution path segments to select(), such as __proto__.tanstackPolluted.
During query compilation, src/query/compiler/select.ts processes select aliases as dot-separated nested paths. The alias is split with alias.split('.'), and each segment is used to build nested objects in the query result. Dangerous segments such as __proto__, constructor, and prototype are not filtered. When the first segment is __proto__, the write cursor can resolve to Object.prototype, causing the next assignment to pollute the global object prototype.
To Reproduce
const {
createCollection,
localOnlyCollectionOptions,
queryOnce
} = require('@tanstack/db');
(async () => {
delete Object.prototype.tanstackPolluted;
const users = createCollection(
localOnlyCollectionOptions({
id: 'poc',
getKey: r => r.id,
initialData: [
{ id: 1, name: 'Alice' }
]
})
);
await users.preload();
await queryOnce(q =>
q
.from({ users })
.select(({ users }) => ({
'__proto__.tanstackPolluted': users.name
}))
);
console.log(({}).tanstackPolluted);
delete Object.prototype.tanstackPolluted;
})();
Steps:
- Install
@tanstack/db@0.6.8.
- Run the JavaScript snippet above with Node.js.
- Observe the output.
Actual output:
Expected behavior
The query result construction should not modify Object.prototype.
The output should be:
Aliases containing dangerous prototype-pollution segments should either be rejected or handled as safe literal field names.
Screenshots
Not applicable.
Desktop (please complete the following information):
- OS: macOS
- Browser: Not applicable
- Version: Node.js runtime
Smartphone (please complete the following information):
Not applicable.
Additional context
Affected package/version:
Affected source area:
src/query/compiler/select.ts
The issue appears to be in alias handling inside select result construction. processNonMergeOp treats aliases as nested paths by splitting on . and writing each segment into the result object. Since prototype-pollution primitives are not blocked, aliases like the following can write to shared prototypes:
__proto__.tanstackPolluted
constructor.prototype.tanstackPolluted
Suggested mitigation:
- Reject alias path segments equal to
__proto__, prototype, or constructor.
- Avoid descending through inherited properties while constructing result objects.
- Use
Object.create(null) for intermediate result containers where appropriate.
- Use own-property checks before reusing nested objects.
Describe the bug
@tanstack/dbis vulnerable to prototype pollution through public query APIs.The root package entry exports
queryOnce,createCollection, andlocalOnlyCollectionOptions. A caller can pass an alias containing prototype-pollution path segments toselect(), such as__proto__.tanstackPolluted.During query compilation,
src/query/compiler/select.tsprocesses select aliases as dot-separated nested paths. The alias is split withalias.split('.'), and each segment is used to build nested objects in the query result. Dangerous segments such as__proto__,constructor, andprototypeare not filtered. When the first segment is__proto__, the write cursor can resolve toObject.prototype, causing the next assignment to pollute the global object prototype.To Reproduce
Steps:
@tanstack/db@0.6.8.Actual output:
Expected behavior
The query result construction should not modify
Object.prototype.The output should be:
Aliases containing dangerous prototype-pollution segments should either be rejected or handled as safe literal field names.
Screenshots
Not applicable.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Not applicable.
Additional context
Affected package/version:
Affected source area:
The issue appears to be in alias handling inside select result construction.
processNonMergeOptreats aliases as nested paths by splitting on.and writing each segment into the result object. Since prototype-pollution primitives are not blocked, aliases like the following can write to shared prototypes:Suggested mitigation:
__proto__,prototype, orconstructor.Object.create(null)for intermediate result containers where appropriate.