From 8c2c94dedaee30a2fdbd27ad0037a25afb355de0 Mon Sep 17 00:00:00 2001 From: Anuj-72 Date: Sun, 2 Aug 2026 12:08:23 +0530 Subject: [PATCH] chore(ci): scan the TypeScript client, and seed the CSP nonce from the CSPRNG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL's language matrix was [python, go], so the VS Code extension's TypeScript was the one shipped tree nothing looked at. Adding javascript-typescript needs no build step (the JS extractor reads source directly) and both Go steps already carry `if: matrix.language == 'go'`, so the new leg skips them. The first finding it reports is ours: the webview's CSP nonce came from Math.random(), the shape every VS Code webview sample uses. That trips js/insecure-randomness, and rightly — a nonce is a security token and has no business coming from a non-cryptographic PRNG. Now randomBytes(16), which keeps the 32-character hex shape the CSP grammar wants. Not a live hole: renderHtml interpolates nothing untrusted and media/chat.js writes through textContent, so a guessed nonce had no injection point to unlock. --- .github/workflows/codeql.yml | 2 +- CHANGELOG.md | 14 ++++++++++++++ extensions/vscode/src/ui/chatView.ts | 11 +++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ac794fc1..2352affc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,7 +34,7 @@ jobs: strategy: fail-fast: false matrix: - language: [python, go] + language: [python, go, javascript-typescript] steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 533659b6..a10dc63c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,20 @@ probes from `scripts/code_quality.py`. - Nine real `.env` keys were reported as typos by `atlas config validate`. +### CodeQL now scans the TypeScript client + +- `javascript-typescript` joins the CodeQL language matrix. The VS Code + extension shipped ~5,100 lines of TS/JS that no scanner looked at, so the + next client lands on a fully covered tree. The extractor needs no build + step, and both Go steps already carry `if: matrix.language == 'go'`. +- The webview's CSP nonce came from `Math.random()` (the shape every VS Code + webview sample uses) and is now `randomBytes(16)` — `js/insecure-randomness` + is in the `security-and-quality` pack, and a security token has no business + coming from a non-cryptographic PRNG. Not a live hole: `renderHtml` + interpolates nothing untrusted and `media/chat.js` writes through + `textContent`, so there was no injection point a guessed nonce could unlock. + + ### Simplification campaign (2026-07-29 → 2026-08) One component-by-component pass over the whole tree — merge the fragments, diff --git a/extensions/vscode/src/ui/chatView.ts b/extensions/vscode/src/ui/chatView.ts index 29fa5d82..7406ae70 100644 --- a/extensions/vscode/src/ui/chatView.ts +++ b/extensions/vscode/src/ui/chatView.ts @@ -3,6 +3,7 @@ // also appended to a transcript so a re-created webview (sidebar closed and // reopened, window reload of the view) can be replayed from scratch. +import { randomBytes } from 'node:crypto'; import { promises as fs } from 'node:fs'; import * as path from 'node:path'; import * as vscode from 'vscode'; @@ -743,10 +744,8 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { } function getNonce(): string { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 32; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; + // A CSP nonce is a security token: it must be unguessable, so it comes + // from the CSPRNG rather than Math.random(). 16 bytes of hex keeps the + // 32-character shape and stays inside the CSP base64-value grammar. + return randomBytes(16).toString('hex'); }