From 615a7130b5e3a392c3d0be096d095ba365253205 Mon Sep 17 00:00:00 2001 From: Hirsch Singhal Date: Mon, 25 May 2026 09:38:54 -0700 Subject: [PATCH 1/6] Fix ghs_ token patterns to support new token format Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/entry-points.js | 22 +++++++++++++++------- src/artifact-scanner.test.ts | 21 +++++++++++++++------ src/artifact-scanner.ts | 25 ++++++++++++++++++------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 78a5f058af..53cf6ec342 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -158049,7 +158049,7 @@ var GITHUB_TOKEN_PATTERNS = [ }, { type: "Server-to-Server Token" /* ServerToServer */, - pattern: /\bghs_[a-zA-Z0-9]{36}\b/g + pattern: /ghs_[A-Za-z0-9._]{36,}/g }, { type: "Refresh Token" /* Refresh */, @@ -158057,7 +158057,7 @@ var GITHUB_TOKEN_PATTERNS = [ }, { type: "App Installation Access Token" /* AppInstallationAccess */, - pattern: /\bghs_[a-zA-Z0-9]{255}\b/g + pattern: /ghs_[A-Za-z0-9._]{36,}/g } ]; function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { @@ -158070,15 +158070,23 @@ function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { } function scanFileForTokens(filePath, relativePath, logger) { const findings = []; + const seenMatches = /* @__PURE__ */ new Set(); try { const content = fs23.readFileSync(filePath, "utf8"); for (const { type: type2, pattern } of GITHUB_TOKEN_PATTERNS) { - const matches = content.match(pattern); - if (matches) { - for (let i = 0; i < matches.length; i++) { - findings.push({ tokenType: type2, filePath: relativePath }); + const regex = new RegExp(pattern.source, pattern.flags); + let matchCount = 0; + for (const match of content.matchAll(regex)) { + const index = match.index; + if (index === void 0 || seenMatches.has(index)) { + continue; } - logger.debug(`Found ${matches.length} ${type2}(s) in ${relativePath}`); + seenMatches.add(index); + findings.push({ tokenType: type2, filePath: relativePath }); + matchCount++; + } + if (matchCount > 0) { + logger.debug(`Found ${matchCount} ${type2}(s) in ${relativePath}`); } } return findings; diff --git a/src/artifact-scanner.test.ts b/src/artifact-scanner.test.ts index 56f99e1138..a0a41f2c56 100644 --- a/src/artifact-scanner.test.ts +++ b/src/artifact-scanner.test.ts @@ -23,6 +23,9 @@ test("makeTestToken", (t) => { t.is(makeTestToken(255).length, 255); }); +const NEW_FORMAT_GHS_TOKEN = + "ghs_abc123.def456.ghi789_abc123.def456.ghi789"; + test("isAuthToken", (t) => { // Undefined for strings that aren't tokens t.is(isAuthToken("some string"), undefined); @@ -32,9 +35,10 @@ test("isAuthToken", (t) => { // Token types for strings that are tokens. t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); + t.is(isAuthToken(NEW_FORMAT_GHS_TOKEN), TokenType.ServerToServer); t.is( isAuthToken(`ghs_${makeTestToken(255)}`), - TokenType.AppInstallationAccess, + TokenType.ServerToServer, ); t.is( isAuthToken(`github_pat_${makeTestToken(22)}_${makeTestToken(59)}`), @@ -52,6 +56,15 @@ test("isAuthToken", (t) => { ]), undefined, ); + t.is( + isAuthToken(NEW_FORMAT_GHS_TOKEN, [ + { + type: TokenType.AppInstallationAccess, + pattern: /ghs_[A-Za-z0-9._]{36,}/g, + }, + ]), + TokenType.AppInstallationAccess, + ); }); const testTokens = [ @@ -76,16 +89,12 @@ const testTokens = [ }, { type: TokenType.ServerToServer, - value: `ghs_${makeTestToken()}`, + value: NEW_FORMAT_GHS_TOKEN, }, { type: TokenType.Refresh, value: `ghr_${makeTestToken()}`, }, - { - type: TokenType.AppInstallationAccess, - value: `ghs_${makeTestToken(255)}`, - }, ]; for (const { type, value, checkPattern } of testTokens) { diff --git a/src/artifact-scanner.ts b/src/artifact-scanner.ts index 5f238811a1..ae53859816 100644 --- a/src/artifact-scanner.ts +++ b/src/artifact-scanner.ts @@ -55,7 +55,7 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ }, { type: TokenType.ServerToServer, - pattern: /\bghs_[a-zA-Z0-9]{36}\b/g, + pattern: /ghs_[A-Za-z0-9._]{36,}/g, }, { type: TokenType.Refresh, @@ -63,7 +63,7 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ }, { type: TokenType.AppInstallationAccess, - pattern: /\bghs_[a-zA-Z0-9]{255}\b/g, + pattern: /ghs_[A-Za-z0-9._]{36,}/g, }, ]; @@ -109,16 +109,27 @@ function scanFileForTokens( logger: Logger, ): TokenFinding[] { const findings: TokenFinding[] = []; + const seenMatches = new Set(); try { const content = fs.readFileSync(filePath, "utf8"); for (const { type, pattern } of GITHUB_TOKEN_PATTERNS) { - const matches = content.match(pattern); - if (matches) { - for (let i = 0; i < matches.length; i++) { - findings.push({ tokenType: type, filePath: relativePath }); + const regex = new RegExp(pattern.source, pattern.flags); + let matchCount = 0; + + for (const match of content.matchAll(regex)) { + const index = match.index; + if (index === undefined || seenMatches.has(index)) { + continue; } - logger.debug(`Found ${matches.length} ${type}(s) in ${relativePath}`); + + seenMatches.add(index); + findings.push({ tokenType: type, filePath: relativePath }); + matchCount++; + } + + if (matchCount > 0) { + logger.debug(`Found ${matchCount} ${type}(s) in ${relativePath}`); } } From df3ab55560b70a5b28de940a31f4fd76dd68ffd9 Mon Sep 17 00:00:00 2001 From: Hirsch Singhal <1666363+hpsin@users.noreply.github.com> Date: Tue, 26 May 2026 09:32:01 -0700 Subject: [PATCH 2/6] Fix ghs_ regex: add dash to character class [A-Za-z0-9._-] --- src/artifact-scanner.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/artifact-scanner.ts b/src/artifact-scanner.ts index ae53859816..95d7f99181 100644 --- a/src/artifact-scanner.ts +++ b/src/artifact-scanner.ts @@ -55,7 +55,7 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ }, { type: TokenType.ServerToServer, - pattern: /ghs_[A-Za-z0-9._]{36,}/g, + pattern: /ghs_[A-Za-z0-9._-]{36,}/g, }, { type: TokenType.Refresh, @@ -63,7 +63,7 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ }, { type: TokenType.AppInstallationAccess, - pattern: /ghs_[A-Za-z0-9._]{36,}/g, + pattern: /ghs_[A-Za-z0-9._-]{36,}/g, }, ]; From b53799fa81226bc949086c285acc6091b7286ba7 Mon Sep 17 00:00:00 2001 From: Hirsch Singhal <1666363+hpsin@users.noreply.github.com> Date: Tue, 26 May 2026 09:32:02 -0700 Subject: [PATCH 3/6] Fix ghs_ regex: add dash to character class [A-Za-z0-9._-] --- src/artifact-scanner.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artifact-scanner.test.ts b/src/artifact-scanner.test.ts index a0a41f2c56..3fb2d34fea 100644 --- a/src/artifact-scanner.test.ts +++ b/src/artifact-scanner.test.ts @@ -60,7 +60,7 @@ test("isAuthToken", (t) => { isAuthToken(NEW_FORMAT_GHS_TOKEN, [ { type: TokenType.AppInstallationAccess, - pattern: /ghs_[A-Za-z0-9._]{36,}/g, + pattern: /ghs_[A-Za-z0-9._-]{36,}/g, }, ]), TokenType.AppInstallationAccess, From 31e72cef951c04787bf825debf7f6b2b79066e8b Mon Sep 17 00:00:00 2001 From: hagould Date: Tue, 26 May 2026 14:56:10 -0700 Subject: [PATCH 4/6] Rebuild lib/ bundle with correct regex Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/entry-points.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 53cf6ec342..abf328166b 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -158049,7 +158049,7 @@ var GITHUB_TOKEN_PATTERNS = [ }, { type: "Server-to-Server Token" /* ServerToServer */, - pattern: /ghs_[A-Za-z0-9._]{36,}/g + pattern: /ghs_[A-Za-z0-9._-]{36,}/g }, { type: "Refresh Token" /* Refresh */, @@ -158057,7 +158057,7 @@ var GITHUB_TOKEN_PATTERNS = [ }, { type: "App Installation Access Token" /* AppInstallationAccess */, - pattern: /ghs_[A-Za-z0-9._]{36,}/g + pattern: /ghs_[A-Za-z0-9._-]{36,}/g } ]; function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { From c90844a05d7aae19f4247fa8fac67f0829cea255 Mon Sep 17 00:00:00 2001 From: hagould Date: Tue, 26 May 2026 15:05:37 -0700 Subject: [PATCH 5/6] Fix prettier formatting --- src/artifact-scanner.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/artifact-scanner.test.ts b/src/artifact-scanner.test.ts index 3fb2d34fea..4634217a5f 100644 --- a/src/artifact-scanner.test.ts +++ b/src/artifact-scanner.test.ts @@ -23,8 +23,7 @@ test("makeTestToken", (t) => { t.is(makeTestToken(255).length, 255); }); -const NEW_FORMAT_GHS_TOKEN = - "ghs_abc123.def456.ghi789_abc123.def456.ghi789"; +const NEW_FORMAT_GHS_TOKEN = "ghs_abc123.def456.ghi789_abc123.def456.ghi789"; test("isAuthToken", (t) => { // Undefined for strings that aren't tokens @@ -36,10 +35,7 @@ test("isAuthToken", (t) => { t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); t.is(isAuthToken(NEW_FORMAT_GHS_TOKEN), TokenType.ServerToServer); - t.is( - isAuthToken(`ghs_${makeTestToken(255)}`), - TokenType.ServerToServer, - ); + t.is(isAuthToken(`ghs_${makeTestToken(255)}`), TokenType.ServerToServer); t.is( isAuthToken(`github_pat_${makeTestToken(22)}_${makeTestToken(59)}`), TokenType.PersonalAccessFineGrained, From eee6a345fee3e492b11b43afb68efa514e5c88a8 Mon Sep 17 00:00:00 2001 From: hagould Date: Tue, 26 May 2026 15:10:03 -0700 Subject: [PATCH 6/6] Collapse AppInstallationAccess into ServerToServer token type --- lib/entry-points.js | 4 ---- src/artifact-scanner.test.ts | 4 ++-- src/artifact-scanner.ts | 5 ----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index abf328166b..bb8e472579 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -158054,10 +158054,6 @@ var GITHUB_TOKEN_PATTERNS = [ { type: "Refresh Token" /* Refresh */, pattern: /\bghr_[a-zA-Z0-9]{36}\b/g - }, - { - type: "App Installation Access Token" /* AppInstallationAccess */, - pattern: /ghs_[A-Za-z0-9._-]{36,}/g } ]; function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { diff --git a/src/artifact-scanner.test.ts b/src/artifact-scanner.test.ts index 4634217a5f..31840ab7cc 100644 --- a/src/artifact-scanner.test.ts +++ b/src/artifact-scanner.test.ts @@ -55,11 +55,11 @@ test("isAuthToken", (t) => { t.is( isAuthToken(NEW_FORMAT_GHS_TOKEN, [ { - type: TokenType.AppInstallationAccess, + type: TokenType.ServerToServer, pattern: /ghs_[A-Za-z0-9._-]{36,}/g, }, ]), - TokenType.AppInstallationAccess, + TokenType.ServerToServer, ); }); diff --git a/src/artifact-scanner.ts b/src/artifact-scanner.ts index 95d7f99181..dc4eba8895 100644 --- a/src/artifact-scanner.ts +++ b/src/artifact-scanner.ts @@ -17,7 +17,6 @@ export enum TokenType { UserToServer = "User-to-Server Token", ServerToServer = "Server-to-Server Token", Refresh = "Refresh Token", - AppInstallationAccess = "App Installation Access Token", } /** A value of this type associates a token type with its pattern. */ @@ -61,10 +60,6 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ type: TokenType.Refresh, pattern: /\bghr_[a-zA-Z0-9]{36}\b/g, }, - { - type: TokenType.AppInstallationAccess, - pattern: /ghs_[A-Za-z0-9._-]{36,}/g, - }, ]; interface TokenFinding {