Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions review-enrichment/src/analyzers/secret-scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,18 @@ const RULES: Rule[] = [
re: /\bsgp_[a-fA-F0-9]{16}_[a-fA-F0-9]{40}(?![A-Za-z0-9_-])/,
confidence: "high",
},
{
// Statsig server secret key: `secret-` + base62 body (SDK validates this prefix).
kind: "statsig_server_secret_key",
re: /\bsecret-[A-Za-z0-9]{20,}(?![A-Za-z0-9_-])/,
confidence: "high",
},
{
// Paddle API key: `pdl_(live|sdbx)_apikey_` + fixed 26/22/3 base62 segments.
kind: "paddle_api_key",
re: /\bpdl_(?:live|sdbx)_apikey_[a-z0-9]{26}_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{3}(?![A-Za-z0-9_-])/,
confidence: "high",
},
{
// Google OAuth 2.0 client secret: `GOCSPX-` + 28 base64url chars.
kind: "google_oauth_client_secret",
Expand Down
47 changes: 47 additions & 0 deletions review-enrichment/test/secret-scan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,53 @@ test("scanPatch does not flag truncated Knock/Sourcegraph tokens or identifier c
);
});

test("scanPatch flags Statsig server secret and Paddle API keys with high confidence", () => {
const fakeStatsigKey = "secret-" + "a".repeat(20);
const statsigFindings = scanPatch("src/config.ts", hunk([`const statsig = "${fakeStatsigKey}";`]));
assert.equal(statsigFindings.length, 1);
assert.equal(statsigFindings[0].kind, "statsig_server_secret_key");
assert.equal(statsigFindings[0].confidence, "high");

const fakePaddleKey = ["pdl_", "live", "_apikey_", "a".repeat(26), "_", "b".repeat(22), "_", "c".repeat(3)].join("");
const paddleFindings = scanPatch("src/config.ts", hunk([`const paddle = "${fakePaddleKey}";`]));
assert.equal(paddleFindings.length, 1);
assert.equal(paddleFindings[0].kind, "paddle_api_key");
assert.equal(paddleFindings[0].confidence, "high");
});

test("scanPatch does not flag truncated Statsig/Paddle keys or identifier continuation", () => {
assert.equal(scanPatch("src/config.ts", hunk([`const statsig = "secret-${"a".repeat(19)}";`])).length, 0);
assert.equal(
scanPatch("src/config.ts", hunk([`const statsig = "secret-${"a".repeat(20)}_suffix";`])).some((f) => f.kind === "statsig_server_secret_key"),
false,
);
assert.equal(
scanPatch("src/config.ts", hunk([`const statsig = "secret-${"a".repeat(20)}-suffix";`])).some((f) => f.kind === "statsig_server_secret_key"),
false,
);

const shortPaddleKey = ["pdl_", "live", "_apikey_", "a".repeat(25), "_", "b".repeat(22), "_", "c".repeat(3)].join("");
assert.equal(
scanPatch("src/config.ts", hunk([`const paddle = "${shortPaddleKey}";`])).some((f) => f.kind === "paddle_api_key"),
false,
);
const paddleSuffixKey = ["pdl_", "live", "_apikey_", "a".repeat(26), "_", "b".repeat(22), "_", "c".repeat(3), "-suffix"].join("");
assert.equal(
scanPatch("src/config.ts", hunk([`const paddle = "${paddleSuffixKey}";`])).some((f) => f.kind === "paddle_api_key"),
false,
);
const paddleUnderscoreKey = ["pdl_", "live", "_apikey_", "a".repeat(26), "_", "b".repeat(22), "_", "c".repeat(3), "_suffix"].join("");
assert.equal(
scanPatch("src/config.ts", hunk([`const paddle = "${paddleUnderscoreKey}";`])).some((f) => f.kind === "paddle_api_key"),
false,
);
const paddleAlphaSuffixKey = ["pdl_", "live", "_apikey_", "a".repeat(26), "_", "b".repeat(22), "_", "c".repeat(3), "z"].join("");
assert.equal(
scanPatch("src/config.ts", hunk([`const paddle = "${paddleAlphaSuffixKey}";`])).some((f) => f.kind === "paddle_api_key"),
false,
);
});

test("scanPatch flags additional high-confidence SaaS/cloud/CI credential formats", () => {
const cases = [
["google_oauth_client_secret", "GOCSPX-" + b62(28)],
Expand Down
Loading