From 23cb8e0eda1e0a29dbb39e1ca98c32a5313d2a0e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:44:53 +0900 Subject: [PATCH 1/4] fix(deps): pin js-yaml to patched release --- frontend/pnpm-lock.yaml | 28 +++++++++++++++------------- frontend/pnpm-workspace.yaml | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 610a0e7ca..018f0382c 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -6,6 +6,7 @@ settings: overrides: brace-expansion: 5.0.9 + js-yaml: 4.3.1 postcss: 8.5.24 sharp: 0.35.0 undici: 8.9.0 @@ -305,8 +306,8 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.6': - resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==} + '@eslint/eslintrc@3.3.7': + resolution: {integrity: sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.5': @@ -1622,6 +1623,7 @@ packages: eslint@9.39.5: resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -1980,8 +1982,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.3.0: - resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true jsdom@30.0.1: @@ -3148,7 +3150,7 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.6': + '@eslint/eslintrc@3.3.7': dependencies: ajv: 6.15.0 debug: 4.4.3 @@ -3156,7 +3158,7 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.3.0 + js-yaml: 4.3.1 minimatch: 3.1.5(patch_hash=5f38b9c5382c1163b0389810f5e4e867519096f3c11a6df0a51d7cafbdfa93e2) strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -4292,7 +4294,7 @@ snapshots: '@next/eslint-plugin-next': 16.2.12 eslint: 9.39.5(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)) eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)) @@ -4315,7 +4317,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -4330,14 +4332,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3) eslint: 9.39.5(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) transitivePeerDependencies: - supports-color @@ -4352,7 +4354,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.5(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -4440,7 +4442,7 @@ snapshots: '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.6 + '@eslint/eslintrc': 3.3.7 '@eslint/js': 9.39.5 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.8 @@ -4826,7 +4828,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.3.0: + js-yaml@4.3.1: dependencies: argparse: 2.0.1 diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml index d028031d2..f9387e42a 100644 --- a/frontend/pnpm-workspace.yaml +++ b/frontend/pnpm-workspace.yaml @@ -15,6 +15,7 @@ supportedArchitectures: overrides: brace-expansion: "5.0.9" + js-yaml: "4.3.1" postcss: "8.5.24" sharp: "0.35.0" undici: 8.9.0 From c3cf4efc478a264a0a010df82d1ea90b48776610 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 10:44:45 +0900 Subject: [PATCH 2/4] test(deps): pin patched js-yaml lock contract --- frontend/src/dependency-lock.security.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 frontend/src/dependency-lock.security.test.ts diff --git a/frontend/src/dependency-lock.security.test.ts b/frontend/src/dependency-lock.security.test.ts new file mode 100644 index 000000000..ce5bb9e21 --- /dev/null +++ b/frontend/src/dependency-lock.security.test.ts @@ -0,0 +1,36 @@ +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +import { describe, expect, it } from "vitest"; + +const workspaceManifest = readFileSync( + fileURLToPath(new URL("../pnpm-workspace.yaml", import.meta.url)), + "utf8", +); +const lockfile = readFileSync( + fileURLToPath(new URL("../pnpm-lock.yaml", import.meta.url)), + "utf8", +); + +describe("frontend dependency lock security contract", () => { + it("pins the patched js-yaml release in the workspace override and lock metadata", () => { + expect(workspaceManifest).toMatch(/^\s{2}js-yaml:\s*"4\.3\.1"\s*$/m); + expect(lockfile).toMatch(/^\s{2}js-yaml:\s*4\.3\.1\s*$/m); + }); + + it("contains no vulnerable js-yaml resolution and routes ESLint through 4.3.1", () => { + const resolvedVersions = [...lockfile.matchAll(/^\s{2}js-yaml@(\d+\.\d+\.\d+):\s*$/gm)] + .map((match) => match[1]); + + expect([...new Set(resolvedVersions)]).toEqual(["4.3.1"]); + expect(lockfile).not.toMatch(/js-yaml@4\.3\.0|js-yaml:\s*4\.3\.0/); + + const snapshots = lockfile.slice(lockfile.indexOf("\nsnapshots:\n")); + const eslintConfigSnapshot = snapshots.match( + /^\s{2}'@eslint\/eslintrc@[^']+':\n(?(?:\s{4,}.*\n)+)/m, + )?.groups?.body; + + expect(eslintConfigSnapshot).toBeDefined(); + expect(eslintConfigSnapshot).toContain("js-yaml: 4.3.1"); + }); +}); From 3f568412da61f12ba36c71765bf915acc8abb85d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 18:12:53 +0900 Subject: [PATCH 3/4] fix(test): preserve ES2017 lock contract compatibility Replace the named capture with an equivalent numbered capture. The existing tsc gate reproduced TS1503 at c3cf4ef; keep the product target and patched dependency lock unchanged. --- frontend/src/dependency-lock.security.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/dependency-lock.security.test.ts b/frontend/src/dependency-lock.security.test.ts index ce5bb9e21..fdaf6f8a8 100644 --- a/frontend/src/dependency-lock.security.test.ts +++ b/frontend/src/dependency-lock.security.test.ts @@ -27,8 +27,8 @@ describe("frontend dependency lock security contract", () => { const snapshots = lockfile.slice(lockfile.indexOf("\nsnapshots:\n")); const eslintConfigSnapshot = snapshots.match( - /^\s{2}'@eslint\/eslintrc@[^']+':\n(?(?:\s{4,}.*\n)+)/m, - )?.groups?.body; + /^\s{2}'@eslint\/eslintrc@[^']+':\n((?:\s{4,}.*\n)+)/m, + )?.[1]; expect(eslintConfigSnapshot).toBeDefined(); expect(eslintConfigSnapshot).toContain("js-yaml: 4.3.1"); From 2e4a1aaf5949d8d9743d670d9e13dd2be917e432 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 9 Sep 2026 17:41:40 +0900 Subject: [PATCH 4/4] test(deps): raise js-yaml security floor to 4.3.2 Record the newly published GHSA-2883-xcg3-v3hh floor as a deterministic RED. The current workspace/lock remain on 4.3.1 so this commit intentionally fails until pnpm 11.5.3 regenerates the dependency artifacts; do not hand-edit generated integrity records. --- frontend/src/dependency-lock.security.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/dependency-lock.security.test.ts b/frontend/src/dependency-lock.security.test.ts index fdaf6f8a8..fb9f5270f 100644 --- a/frontend/src/dependency-lock.security.test.ts +++ b/frontend/src/dependency-lock.security.test.ts @@ -13,17 +13,17 @@ const lockfile = readFileSync( ); describe("frontend dependency lock security contract", () => { - it("pins the patched js-yaml release in the workspace override and lock metadata", () => { - expect(workspaceManifest).toMatch(/^\s{2}js-yaml:\s*"4\.3\.1"\s*$/m); - expect(lockfile).toMatch(/^\s{2}js-yaml:\s*4\.3\.1\s*$/m); + it("pins js-yaml at the current reviewed patched 4.x release", () => { + expect(workspaceManifest).toMatch(/^\s{2}js-yaml:\s*"4\.3\.2"\s*$/m); + expect(lockfile).toMatch(/^\s{2}js-yaml:\s*4\.3\.2\s*$/m); }); - it("contains no vulnerable js-yaml resolution and routes ESLint through 4.3.1", () => { + it("contains no pre-4.3.2 js-yaml resolution and routes ESLint through 4.3.2", () => { const resolvedVersions = [...lockfile.matchAll(/^\s{2}js-yaml@(\d+\.\d+\.\d+):\s*$/gm)] .map((match) => match[1]); - expect([...new Set(resolvedVersions)]).toEqual(["4.3.1"]); - expect(lockfile).not.toMatch(/js-yaml@4\.3\.0|js-yaml:\s*4\.3\.0/); + expect([...new Set(resolvedVersions)]).toEqual(["4.3.2"]); + expect(lockfile).not.toMatch(/js-yaml@4\.3\.[01]|js-yaml:\s*4\.3\.[01]/); const snapshots = lockfile.slice(lockfile.indexOf("\nsnapshots:\n")); const eslintConfigSnapshot = snapshots.match( @@ -31,6 +31,6 @@ describe("frontend dependency lock security contract", () => { )?.[1]; expect(eslintConfigSnapshot).toBeDefined(); - expect(eslintConfigSnapshot).toContain("js-yaml: 4.3.1"); + expect(eslintConfigSnapshot).toContain("js-yaml: 4.3.2"); }); });