Skip to content

Tracking PR - TigerBeetle Ledger#1269

Draft
lewisdaly wants to merge 3 commits intomainfrom
tigerbeetle-ledger
Draft

Tracking PR - TigerBeetle Ledger#1269
lewisdaly wants to merge 3 commits intomainfrom
tigerbeetle-ledger

Conversation

@lewisdaly
Copy link
Copy Markdown
Contributor

This draft PR tracks the changes between the tigerbeetle-ledger and main branches.

I'm periodically rebasing tigerbeetle-ledger onto main on a regular basis, so the commits we see here will be the merge commits from each subsequent TigerBeetle-related PR onto tigerbeetle-ledger.

Comment thread src/lib/config/util.ts
) {
deepMerge(valTarget, valSource as any)
} else {
target[key] = valSource as T[keyof T]

Check warning

Code scanning / CodeQL

Prototype-polluting function Medium

Properties are copied from
source
to
target
without guarding against prototype pollution.

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.

Suggested changeset 1
src/lib/config/util.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/config/util.ts b/src/lib/config/util.ts
--- a/src/lib/config/util.ts
+++ b/src/lib/config/util.ts
@@ -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]
 
EOF
@@ -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]

Copilot is powered by AI and may make mistakes. Always verify output.
* 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.
@lewisdaly lewisdaly force-pushed the tigerbeetle-ledger branch from 0d29384 to 2b74f70 Compare April 10, 2026 11:06
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
8.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants