From 089dad6003725f59901e9f9fcb3dbc0925d179c5 Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Tue, 9 Jun 2026 16:12:45 +0000 Subject: [PATCH] fix(ci): drop the shell in the grammar monitor's github fetch (CodeQL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL flagged the GitHub-tarball fetch — it used `bash -c "gh api …/tarball/$ref > src.tgz && tar xzf src.tgz"`, interpolating the API-derived ref into a shell command (the shell-command-injection family: "this shell command depends on an uncontrolled file name"). Replace it with a shell-free path: capture `gh api`'s binary tarball as a Buffer via execFileSync, write it to a fixed file, and extract with execFileSync('tar', …). No shell, no injection surface. Verified the dart/proto fetch + ABI read still work. --- .github/scripts/update-vendored-grammars.mjs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/scripts/update-vendored-grammars.mjs b/.github/scripts/update-vendored-grammars.mjs index aa2fffa74..957200e77 100644 --- a/.github/scripts/update-vendored-grammars.mjs +++ b/.github/scripts/update-vendored-grammars.mjs @@ -105,10 +105,19 @@ function fetchSource(g, ref) { sh('tar', ['xzf', tgz], { cwd: work }); return path.join(work, 'package'); } - // github tarball at the resolved sha - sh('bash', ['-c', `gh api repos/${g.github}/tarball/${ref} > src.tgz && tar xzf src.tgz`], { - cwd: work, - }); + // github tarball at the resolved sha. Download + extract WITHOUT a shell + // (no `bash -c`/redirect): `gh api` writes the binary tarball to stdout, which + // we capture as a Buffer and write to a fixed path, then extract with execFile. + // Avoids the shell-command-injection surface CodeQL flags when an API-derived + // ref is interpolated into a `bash -c` string. + const tgz = path.join(work, 'src.tgz'); + fs.writeFileSync( + tgz, + execFileSync('gh', ['api', `repos/${g.github}/tarball/${ref}`], { + maxBuffer: 512 * 1024 * 1024, + }), + ); + sh('tar', ['xzf', tgz], { cwd: work }); const dir = fs.readdirSync(work).find((f) => fs.statSync(path.join(work, f)).isDirectory()); return path.join(work, dir); }