diff --git a/review-enrichment/src/analyzers/secret-scan.ts b/review-enrichment/src/analyzers/secret-scan.ts index 1ecaeb76af..270426501f 100644 --- a/review-enrichment/src/analyzers/secret-scan.ts +++ b/review-enrichment/src/analyzers/secret-scan.ts @@ -367,6 +367,18 @@ const RULES: Rule[] = [ re: /\bsk-api-[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/, confidence: "high", }, + { + // Axiom API token: `xaat-` + UUID-shaped body (edge ingest/query operations). + kind: "axiom_api_token", + re: /\bxaat-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(?![A-Za-z0-9_-])/, + confidence: "high", + }, + { + // Axiom personal access token: `xapt-` + UUID-shaped body. + kind: "axiom_personal_token", + re: /\bxapt-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(?![A-Za-z0-9_-])/, + confidence: "high", + }, { // Google OAuth 2.0 client secret: `GOCSPX-` + 28 base64url chars. kind: "google_oauth_client_secret", diff --git a/review-enrichment/test/secret-scan.test.ts b/review-enrichment/test/secret-scan.test.ts index 70d4a77eb7..e9cd75f441 100644 --- a/review-enrichment/test/secret-scan.test.ts +++ b/review-enrichment/test/secret-scan.test.ts @@ -1035,6 +1035,64 @@ test("scanPatch does not flag truncated MiniMax keys or identifier continuation" ); }); +test("scanPatch flags Axiom API and personal access tokens with high confidence", () => { + const fakeAxiomApiToken = ["xaat-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901"].join(""); + const axiomApiFindings = scanPatch("src/config.ts", hunk([`const axiom = "${fakeAxiomApiToken}";`])); + assert.equal(axiomApiFindings.length, 1); + assert.equal(axiomApiFindings[0].kind, "axiom_api_token"); + assert.equal(axiomApiFindings[0].confidence, "high"); + + const fakeAxiomPat = ["xapt-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901"].join(""); + const axiomPatFindings = scanPatch("src/config.ts", hunk([`const axiom = "${fakeAxiomPat}";`])); + assert.equal(axiomPatFindings.length, 1); + assert.equal(axiomPatFindings[0].kind, "axiom_personal_token"); + assert.equal(axiomPatFindings[0].confidence, "high"); +}); + +test("scanPatch does not flag truncated Axiom tokens or identifier continuation", () => { + const shortAxiomApiToken = ["xaat-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "01234567890"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${shortAxiomApiToken}";`])).some((f) => f.kind === "axiom_api_token"), + false, + ); + const axiomApiSuffixToken = ["xaat-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "-suffix"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomApiSuffixToken}";`])).some((f) => f.kind === "axiom_api_token"), + false, + ); + const axiomApiUnderscoreToken = ["xaat-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "_suffix"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomApiUnderscoreToken}";`])).some((f) => f.kind === "axiom_api_token"), + false, + ); + const axiomApiAlphaSuffixToken = ["xaat-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "z"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomApiAlphaSuffixToken}";`])).some((f) => f.kind === "axiom_api_token"), + false, + ); + + const shortAxiomPat = ["xapt-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "01234567890"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${shortAxiomPat}";`])).some((f) => f.kind === "axiom_personal_token"), + false, + ); + const axiomPatSuffixToken = ["xapt-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "-suffix"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomPatSuffixToken}";`])).some((f) => f.kind === "axiom_personal_token"), + false, + ); + const axiomPatUnderscoreToken = ["xapt-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "_suffix"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomPatUnderscoreToken}";`])).some((f) => f.kind === "axiom_personal_token"), + false, + ); + const axiomPatAlphaSuffixToken = ["xapt-", "01234567", "-", "0123", "-", "4567", "-", "8901", "-", "012345678901", "z"].join(""); + assert.equal( + scanPatch("src/config.ts", hunk([`const axiom = "${axiomPatAlphaSuffixToken}";`])).some((f) => f.kind === "axiom_personal_token"), + false, + ); +}); + test("scanPatch flags additional high-confidence SaaS/cloud/CI credential formats", () => { const cases = [ ["google_oauth_client_secret", "GOCSPX-" + b62(28)],