Conversation
| ) { | ||
| deepMerge(valTarget, valSource as any) | ||
| } else { | ||
| target[key] = valSource as T[keyof T] |
Check warning
Code scanning / CodeQL
Prototype-polluting function Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
In general, to fix prototype pollution in deep merge / deep assignment helpers, you either (a) block dangerous property names (__proto__, constructor, prototype) from being merged at all, or (b) only recurse into properties that already exist as own properties on the destination object, while still blocking the dangerous names. Both strategies prevent writes to Object.prototype and other prototypes.
For this specific deepMerge function, the minimal, behavior-preserving change is to add a guard at the start of the for loop that skips over dangerous keys before any access or assignment to target[key] or recursive merge. This leaves all existing semantics intact for normal keys and still allows arbitrary structure merging, but prevents merges for __proto__, constructor, and prototype. We do not need to change callers or function signatures, and we do not need any new imports or external libraries. The change should be done in src/lib/config/util.ts around lines 507–524, inserting a small conditional that continues the loop when the key is one of those reserved names.
Concretely: in deepMerge, after obtaining key in the for loop and before using it to access source[key] or target[key], insert a guard:
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue
}This single check eliminates the prototype pollution vector flagged by CodeQL while not altering merge behavior for all other keys.
| @@ -506,6 +506,11 @@ | ||
| */ | ||
| export function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T { | ||
| for (const key of Object.keys(source) as Array<keyof T>) { | ||
| // Guard against prototype pollution by skipping dangerous keys. | ||
| if (key === '__proto__' || key === 'constructor' || key === 'prototype') { | ||
| continue | ||
| } | ||
|
|
||
| const valSource = source[key] | ||
| const valTarget = target[key] | ||
|
|
* add typescript config to project, move ./migrations and ./seeds into ./src to ensure they get built by ts * delete ./config/knexfile.js in favour of src/knexfile.js * add `npm run build` step to Dockerfile * update seed test files with new path * chore: formatting migrations * chore: add convenience types * update imports for ts, improve loggingPlugin context * chore: remove already removed loggingPlugin. (it got added back during the last merge) * chore: revert minor changes * chore: fix formatting issues * remove seeds and migrations dirs from Dockerfile * chore: force fast-xml-parser:5.3.4 to avoid CVE GHSA-37qj-frw5-hhjh * chore: fix docker build step * fix: Dockerfile copy /dist * chore: update dependencies
…lidation (#1247) feat: Add strict typing to config values, along with comprehensive validation. We also started a new set of unit tests, which use the native nodejs test runner instead of tape. The goal is that we can eventually migrate away from tape, giving us the ability to remove a number of test dependencies, ensure better test isolation and improve the developer experience. To that end, `src/testing/run.ts` becomes a new common entrypoint for all of our local test commands, which gives us a good foundation to replace the shell scripts (see [make.ts](https://matklad.github.io/2026/01/27/make-ts.html) for inspiration) and improve the overall DX.
0d29384 to
2b74f70
Compare
|


This draft PR tracks the changes between the
tigerbeetle-ledgerandmainbranches.I'm periodically rebasing
tigerbeetle-ledgerontomainon a regular basis, so the commits we see here will be the merge commits from each subsequent TigerBeetle-related PR ontotigerbeetle-ledger.