diff --git a/src/cli.test.ts b/src/cli.test.ts index 29d67773..a1017405 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -110,6 +110,15 @@ describe('cli', () => { expect(result).not.toContain('ghp_'); }); + it('should redact stateless GitHub app installation tokens', () => { + const token = `ghs_${'A'.repeat(170)}.${'b'.repeat(170)}-${'c'.repeat(170)}_${'d'.repeat(170)}`; + const command = `echo ${token}`; + const result = redactSecrets(command); + + expect(result).toBe('echo ***REDACTED***'); + expect(result).not.toContain(token); + }); + it('should redact multiple secrets in one command', () => { const command = 'GITHUB_TOKEN=ghp_token API_KEY=secret curl -H "Authorization: Bearer ghp_bearer"'; const result = redactSecrets(command); diff --git a/src/dlp.test.ts b/src/dlp.test.ts index f97a4195..613a9e0a 100644 --- a/src/dlp.test.ts +++ b/src/dlp.test.ts @@ -52,7 +52,15 @@ describe('DLP Patterns', () => { const matchingRegexes = findMatchingDlpRegexes( 'https://api.example.com/?key=ghs_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij' ); - expect(matchingRegexes).toContain('ghs_[a-zA-Z0-9]{36}'); + expect(matchingRegexes).toContain('ghs_[A-Za-z0-9._-]{36,}'); + }); + + it('should detect stateless GitHub App installation token (ghs_ JWT format)', () => { + const jwtLikeToken = `ghs_${'A'.repeat(170)}.${'b'.repeat(170)}-${'c'.repeat(170)}_${'d'.repeat(170)}`; + const matchingRegexes = findMatchingDlpRegexes( + `https://api.example.com/?key=${jwtLikeToken}` + ); + expect(matchingRegexes).toContain('ghs_[A-Za-z0-9._-]{36,}'); }); it('should detect GitHub App user-to-server token (ghu_)', () => { diff --git a/src/dlp.ts b/src/dlp.ts index 3192a253..1cf895f7 100644 --- a/src/dlp.ts +++ b/src/dlp.ts @@ -52,7 +52,7 @@ const DLP_PATTERNS: DlpPattern[] = [ { name: 'GitHub App Installation Token', description: 'GitHub App installation access token (ghs_)', - regex: 'ghs_[a-zA-Z0-9]{36}', + regex: 'ghs_[A-Za-z0-9._-]{36,}', }, { name: 'GitHub App User-to-Server Token', diff --git a/src/redact-secrets.ts b/src/redact-secrets.ts index b79cc62b..236935d4 100644 --- a/src/redact-secrets.ts +++ b/src/redact-secrets.ts @@ -10,5 +10,5 @@ export function redactSecrets(command: string): string { // Redact tokens in environment variables (TOKEN, SECRET, PASSWORD, KEY, API_KEY, etc) .replace(/(\w*(?:TOKEN|SECRET|PASSWORD|KEY|AUTH)\w*)=(\S+)/gi, '$1=***REDACTED***') // Redact GitHub tokens (ghp_, gho_, ghu_, ghs_, ghr_) - .replace(/\b(gh[pousr]_[a-zA-Z0-9]{36,255})/g, '***REDACTED***'); + .replace(/\b(gh[pousr]_[A-Za-z0-9._-]{36,})/g, '***REDACTED***'); }