fix(security): crypto-secure cloud-agent IDs + exact-hostname check (CodeQL #251, #252)

- #251 (Insecure randomness): baseAgent.generateTaskId/generateActivityId used
  Math.random().toString(36) for IDs that flow into session/external identifiers
  (e.g. jules.ts task externalId). Switched to crypto randomBytes(8).toString("hex").
- #252 (Incomplete URL substring sanitization): the antigravity discovery test
  matched the upstream host via url.includes("…googleapis.com"), which a look-alike
  host could bypass. Switched to an exact `new URL(url).hostname === …` comparison.
This commit is contained in:
diegosouzapw
2026-05-22 15:09:07 -03:00
parent 1ea91b6c71
commit 34e62d8725
2 changed files with 9 additions and 3 deletions

View File

@@ -1,3 +1,4 @@
import { randomBytes } from "node:crypto";
import type {
CloudAgentTask,
CloudAgentStatus,
@@ -86,10 +87,12 @@ export abstract class CloudAgentBase {
}
protected generateTaskId(): string {
return `task_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
// Cryptographically secure suffix (not Math.random) — task IDs flow into
// session/external identifiers, so they must be unpredictable (CodeQL js/insecure-randomness).
return `task_${Date.now()}_${randomBytes(8).toString("hex")}`;
}
protected generateActivityId(): string {
return `act_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
return `act_${Date.now()}_${randomBytes(8).toString("hex")}`;
}
}

View File

@@ -152,7 +152,10 @@ describe("ensureAntigravityProjectAssigned", () => {
const mockFetch = async (url: string, _init?: RequestInit): Promise<Response> => {
hitUrls.push(url);
if (url.includes("daily-cloudcode-pa.googleapis.com")) {
// Exact hostname match (not substring .includes) so the check can't be fooled by a
// look-alike host like daily-cloudcode-pa.googleapis.com.evil.com (CodeQL
// js/incomplete-url-substring-sanitization).
if (new URL(url).hostname === "daily-cloudcode-pa.googleapis.com") {
// First URL fails
return new Response("not found", { status: 404 });
}