From 04002981506a5675f8efe7944bb6b8468cf3d7bf Mon Sep 17 00:00:00 2001 From: Avi Fenesh Date: Sat, 30 May 2026 12:45:29 +0300 Subject: [PATCH 1/2] ci/security: pin actions, add workflow permissions, sanitize log Clears the open CodeQL medium alerts in this repo: - actions/unpinned-tag: pin dtolnay/rust-toolchain, Swatinem/rust-cache and softprops/action-gh-release to commit SHAs in ci.yml and release.yml. - actions/missing-workflow-permissions: add top-level `permissions: contents: read` to ci.yml (all four jobs are read-only build/test). - js/log-injection: strip CR/LF from the download error detail before logging in npm/scripts/postinstall.js. --- .github/workflows/ci.yml | 9 ++++++--- .github/workflows/release.yml | 6 +++--- npm/scripts/postinstall.js | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bba6ba5..02625b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: branches: ["main"] pull_request: +permissions: + contents: read + jobs: rust: name: Rust and script checks @@ -45,12 +48,12 @@ jobs: xvfb - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: components: clippy, rustfmt - name: Cache cargo - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: Format run: cargo fmt --check @@ -83,7 +86,7 @@ jobs: uses: actions/checkout@v6 - name: Install Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable - name: Install cargo-audit run: cargo install cargo-audit --locked diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a2bb18b..31ce6be 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,7 +70,7 @@ jobs: xvfb - name: Install Rust (stable) with target - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: # Register the rustup target so cargo can cross-compile; on the # native ARM runner this is still needed when --target is passed. @@ -78,7 +78,7 @@ jobs: # Cache keyed per target so x86_64 and aarch64 don't overwrite each other. - name: Cache cargo - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: ${{ matrix.target }} @@ -98,7 +98,7 @@ jobs: # error) while still exercising the build. - name: Upload release asset if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3 with: tag_name: ${{ github.ref_name }} files: agent-workspace-linux-${{ matrix.target }} diff --git a/npm/scripts/postinstall.js b/npm/scripts/postinstall.js index da75c0d..a8cf0b5 100644 --- a/npm/scripts/postinstall.js +++ b/npm/scripts/postinstall.js @@ -134,7 +134,10 @@ function download(url, tmpFile, maxRedirects = 5) { try { fs.unlinkSync(tmpPath); } catch (_) {} - console.error(`\nagent-workspace-linux: download failed — ${err.message}`); + // Strip CR/LF from the error detail before logging so a value that flows + // in from the download URL/target cannot forge extra log lines. + const detail = String(err.message).replace(/[\r\n]+/g, ' '); + console.error(`\nagent-workspace-linux: download failed — ${detail}`); process.exit(1); } From f9cd9133b555082bebaeb3e1b35611928a1854ab Mon Sep 17 00:00:00 2001 From: Avi Fenesh Date: Sat, 30 May 2026 12:53:34 +0300 Subject: [PATCH 2/2] fix(security): log a static message on download failure (log-injection) CodeQL did not accept the newline-stripping sanitizer on the URL-derived error text. Log a fixed guidance message instead of interpolating err.message; the request URL is already printed above for debugging. --- npm/scripts/postinstall.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/npm/scripts/postinstall.js b/npm/scripts/postinstall.js index a8cf0b5..aec1fa8 100644 --- a/npm/scripts/postinstall.js +++ b/npm/scripts/postinstall.js @@ -134,10 +134,15 @@ function download(url, tmpFile, maxRedirects = 5) { try { fs.unlinkSync(tmpPath); } catch (_) {} - // Strip CR/LF from the error detail before logging so a value that flows - // in from the download URL/target cannot forge extra log lines. - const detail = String(err.message).replace(/[\r\n]+/g, ' '); - console.error(`\nagent-workspace-linux: download failed — ${detail}`); + // The download error text embeds the request URL (built from + // package.json's version + the target triple). Log a fixed message rather + // than interpolating that value, to avoid a log-injection sink; the URL + // itself is already printed above for debugging. + console.error( + "\nagent-workspace-linux: download failed. Verify the release exists " + + "for your platform and that the version in package.json matches " + + "(see the URL logged above)." + ); process.exit(1); }