fix: redact additional GitLab token prefixes [AI] (#112954)

* fix: redact additional GitLab token prefixes

* fix: cover GitLab runner token variants

* test: construct GitLab redaction fixtures

* fix: consume full GitLab OAuth tokens

* fix: preserve long GitLab OAuth redaction

* fix: keep legacy OAuth token masking
This commit is contained in:
Pavan Kumar Gondhi
2026-07-24 14:15:15 +05:30
committed by GitHub
parent adf78cefbd
commit 91ea4e03fa
2 changed files with 63 additions and 3 deletions
+48 -1
View File
@@ -1434,9 +1434,56 @@ describe("redactSensitiveText", () => {
}
});
it("masks additional GitLab token prefixes through the default fast path", () => {
const dashToken = (prefix: string, suffix: string): string => [prefix, suffix].join("-");
const repeatedDashToken = (prefix: string, length: number): string =>
dashToken(prefix, "A".repeat(length));
const legacyOauthToken = dashToken("gloas", "a".repeat(32));
const longHexOauthToken = dashToken("gloas", "a".repeat(80));
const mixedOauthToken = dashToken("gloas", `${"a".repeat(32)}Z${"b".repeat(31)}`);
const tokens = [
legacyOauthToken,
longHexOauthToken,
mixedOauthToken,
repeatedDashToken("gldt", 20),
dashToken("glcbt", `a1B2_${"A".repeat(20)}`),
repeatedDashToken("glptt", 40),
repeatedDashToken("glft", 20),
dashToken("glft", "a0b1-123_"),
repeatedDashToken("glimt", 25),
repeatedDashToken("glagent", 50),
repeatedDashToken("glwt", 20),
repeatedDashToken("glsoat", 20),
repeatedDashToken("glffct", 20),
dashToken("glrt", `t1_${"A".repeat(20)}`),
dashToken("glrt", "2CR8_eVxiioB1QmzPZwa"),
dashToken("glrt", "ABCdef1234567890xyzW"),
dashToken("glrt", `${"A".repeat(27)}.01.${"a".repeat(9)}`),
dashToken("glrtr", `${"A".repeat(27)}.01.${"a".repeat(9)}`),
`GR1348941${"A".repeat(20)}`,
`_gitlab_session=${"A".repeat(32)}`,
];
for (const token of tokens) {
expect(redactSensitiveText(token, { mode: "tools" }), token).not.toContain(token);
}
expect(redactSensitiveText(mixedOauthToken, { mode: "tools" })).not.toContain(
mixedOauthToken.slice("gloas-".length + 32),
);
expect(redactSensitiveText(longHexOauthToken, { mode: "tools" })).not.toContain(
longHexOauthToken.slice("gloas-".length + 64),
);
expect(redactSensitiveText(`${legacyOauthToken}_suffix`, { mode: "tools" })).not.toContain(
legacyOauthToken,
);
expect(redactSensitiveText(`${longHexOauthToken}_suffix`, { mode: "tools" })).not.toContain(
`${longHexOauthToken.slice("gloas-".length + 64)}_suffix`,
);
});
it("does not redact ordinary identifiers containing short token-prefix substrings", () => {
const input = [
"npm_telegram_package_spec ask_openclaw_query_patterns team_management risk_assessment glpat-docs dapi-example sbp_short nfp_site CCIPAT_docs ATATT-example fw-tooshort fw_tooshort fpk_tooshort",
"npm_telegram_package_spec ask_openclaw_query_patterns team_management risk_assessment glpat-docs gloas-docs gldt-docs glcbt-docs glptt-docs glft-docs glimt-docs glagent-docs glwt-docs glsoat-docs glffct-docs glrt-docs glrtr-docs GR1348941-docs _gitlab_session=short dapi-example sbp_short nfp_site CCIPAT_docs ATATT-example fw-tooshort fw_tooshort fpk_tooshort",
`fixturefw-${"C".repeat(40)}`,
`fixture_fw_${"A".repeat(40)}`,
`fixture_fpk_${"B".repeat(40)}`,
+15 -2
View File
@@ -243,7 +243,20 @@ const DEFAULT_REDACT_PATTERNS: string[] = [
String.raw`(ghs_[A-Za-z0-9]{10,})`,
String.raw`(ghr_[A-Za-z0-9]{10,})`,
String.raw`(glpat-[A-Za-z0-9._=\-]{20,})`,
String.raw`(gloas-[A-Fa-f0-9]{32,})`,
String.raw`(gloas-(?:[A-Fa-f0-9]{65,}|[A-Za-z0-9_-]{64}|[A-Fa-f0-9]{32,}))`,
String.raw`(gldt-[A-Za-z0-9_-]{20,})`,
String.raw`(glcbt-[A-Za-z0-9]{1,5}_[A-Za-z0-9_-]{20,})`,
String.raw`(glptt-[A-Za-z0-9_-]{40,})`,
String.raw`(glft-(?:[A-Za-z0-9_-]{20,}|[a-h0-9]+-[0-9]+_))`,
String.raw`(glimt-[A-Za-z0-9_-]{25,})`,
String.raw`(glagent-[A-Za-z0-9_-]{50,})`,
String.raw`(glwt-[A-Za-z0-9_-]{20,})`,
String.raw`(glsoat-[A-Za-z0-9_-]{20,})`,
String.raw`(glffct-[A-Za-z0-9_-]{20,})`,
String.raw`(glrt-[A-Za-z0-9._-]{20,})`,
String.raw`(glrtr?-[A-Za-z0-9_-]{27,300}\.[0-9a-z]{2}\.[0-9a-z]{9})`,
String.raw`(GR1348941[A-Za-z0-9_-]{20,})`,
String.raw`(_gitlab_session=[A-Za-z0-9%._-]{20,})`,
String.raw`(xox[baprs]-[A-Za-z0-9-]{10,})`,
String.raw`(xapp-[A-Za-z0-9-]{10,})`,
String.raw`(https:\/\/hooks\.slack\.com\/(?:services\/T[A-Z0-9]+\/B[A-Z0-9]+|workflows\/T[A-Z0-9]+\/A[A-Z0-9]+\/[0-9]{17,19})\/[A-Za-z0-9]{20,})`,
@@ -334,7 +347,7 @@ const DEFAULT_REDACT_PREFILTER_SOURCES: string[] = [
// URL userinfo and connection-string password slots (`scheme://user:pass@host`).
String.raw`:\/\/[^\/\s:@]*:[^\/\s@]+@`,
// Vendor token prefixes and webhook hosts, ordered like DEFAULT_REDACT_PATTERNS.
String.raw`sk-|gh[opsur]_|github_pat_|glpat-|gloas-|xox[baprs]-|xapp-|hooks\.slack\.com|discord|gsk_|AIza|ya29\.|1\/\/0|eyJ|pplx-|fal_|fc-|bb_live_|gAAAA|[sr]k_(?:live|test)_|\bSG\.|npm_|pypi-|do[opr]_v1_|dp\.(?:ct|pt|sa|st|scim|audit)\.|dckr_|bkua_|CCIPAT_|sbp_|dapi[0-9a-f]|dd[pw]_|glsa_|nfp_|CFPAT-|ATCTT3|ATATT|ATBB|BBDC-|HRKU-|pat-(?:eu|na)1-|apify_api_|FlyV1|fio-u-|tvly-|exa_|syt_|retaindb_|mem0_|brv_|xai-|fw-|fw_|fpk_`,
String.raw`sk-|gh[opsur]_|github_pat_|glpat-|gloas-|gldt-|glcbt-|glptt-|glft-|glimt-|glagent-|glwt-|glsoat-|glffct-|glrt-|glrtr-|GR1348941|_gitlab_session=|xox[baprs]-|xapp-|hooks\.slack\.com|discord|gsk_|AIza|ya29\.|1\/\/0|eyJ|pplx-|fal_|fc-|bb_live_|gAAAA|[sr]k_(?:live|test)_|\bSG\.|npm_|pypi-|do[opr]_v1_|dp\.(?:ct|pt|sa|st|scim|audit)\.|dckr_|bkua_|CCIPAT_|sbp_|dapi[0-9a-f]|dd[pw]_|glsa_|nfp_|CFPAT-|ATCTT3|ATATT|ATBB|BBDC-|HRKU-|pat-(?:eu|na)1-|apify_api_|FlyV1|fio-u-|tvly-|exa_|syt_|retaindb_|mem0_|brv_|xai-|fw-|fw_|fpk_`,
String.raw`(?:^|[^A-Za-z0-9_])(?:am_|sk_)`,
String.raw`A[KS]IA[A-Z0-9]|AKID|LTAI|hf_|api_org_|r8_`,
AWS_SECRET_ACCESS_KEY_VALUE_PATTERN,