fix(logging): redact Telegram tokens across chunk boundaries (#103861)

This commit is contained in:
Vincent Koc
2026-07-10 11:20:46 -07:00
committed by GitHub
parent eb7613cecd
commit b56bad33f2
2 changed files with 29 additions and 3 deletions
+18
View File
@@ -955,6 +955,24 @@ describe("redactSensitiveText", () => {
}
});
it("masks Telegram bot tokens that cross bounded-replacement chunk boundaries", () => {
const chunkSize = 16_384;
const credential = `123456:${"A".repeat(28)}WXYZ`;
const cases = [
{ token: `bot${credential}`, redacted: "bot123456…WXYZ" },
{ token: credential, redacted: "123456…WXYZ" },
];
for (const { token, redacted } of cases) {
const tokenStart = chunkSize - 12;
const prefix = `${"x".repeat(tokenStart - 1)} `;
const suffix = ` ${"y".repeat(chunkSize * 2)}`;
expect(redactSensitiveText(`${prefix}${token}${suffix}`, { mode: "tools" })).toBe(
`${prefix}${redacted}${suffix}`,
);
}
});
it("does not corrupt base64 blobs that embed token-prefix shapes", () => {
// Tiny-PNG base64 contains a gAAAA run from zero-filled IHDR bytes; pure-base64-alphabet
// prefixes must not fire mid-blob or media payloads get mangled.
+11 -3
View File
@@ -127,12 +127,18 @@ const STANDALONE_ASSIGNMENT_REDACT_PATTERN = String.raw`(^|[\s,;])(?:${STANDALON
// data-URL media is never corrupted while tokens in URL paths or assignments still redact.
const BASE64_SAFE_TOKEN_BOUNDARY = String.raw`(^|[^A-Za-z0-9])(?<!;base64,[A-Za-z0-9+/=]*)`;
const IDENTIFIER_SAFE_TOKEN_BOUNDARY = String.raw`(^|[^A-Za-z0-9_])`;
const TELEGRAM_BOT_TOKEN_REDACT_PATTERN = String.raw`\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b`;
const TELEGRAM_TOKEN_REDACT_PATTERN = String.raw`\b(\d{6,}:[A-Za-z0-9_-]{20,})\b`;
const SHELL_REFERENCE_PRESERVING_PATTERN_SOURCES = new Set([
ENV_ASSIGNMENT_REDACT_PATTERN,
ESCAPED_ENV_ASSIGNMENT_REDACT_PATTERN,
STANDALONE_ASSIGNMENT_QUOTED_REDACT_PATTERN,
STANDALONE_ASSIGNMENT_REDACT_PATTERN,
]);
const CHUNK_UNSAFE_PATTERN_SOURCES = new Set([
TELEGRAM_BOT_TOKEN_REDACT_PATTERN,
TELEGRAM_TOKEN_REDACT_PATTERN,
]);
const shellReferencePreservingPatterns = new WeakSet<RegExp>();
// Patterns whose left-context assertions or complete token can cross a chunk boundary must run
// against the full string; chunking can invent a `^` boundary or split the secret itself.
@@ -251,8 +257,8 @@ const DEFAULT_REDACT_PATTERNS: string[] = [
String.raw`(api_org_[A-Za-z0-9]{20,})`,
String.raw`(r8_[A-Za-z0-9]{10,})`,
// Telegram Bot API URLs embed the token as `/bot<token>/...` (no word-boundary before digits).
String.raw`\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b`,
String.raw`\b(\d{6,}:[A-Za-z0-9_-]{20,})\b`,
TELEGRAM_BOT_TOKEN_REDACT_PATTERN,
TELEGRAM_TOKEN_REDACT_PATTERN,
];
let defaultResolvedPatterns: RegExp[] | undefined;
@@ -323,7 +329,9 @@ function parsePattern(raw: RedactPattern): RegExp | null {
if (
pattern &&
typeof raw === "string" &&
(raw.startsWith(BASE64_SAFE_TOKEN_BOUNDARY) || raw.startsWith(IDENTIFIER_SAFE_TOKEN_BOUNDARY))
(raw.startsWith(BASE64_SAFE_TOKEN_BOUNDARY) ||
raw.startsWith(IDENTIFIER_SAFE_TOKEN_BOUNDARY) ||
CHUNK_UNSAFE_PATTERN_SOURCES.has(raw))
) {
chunkUnsafePatterns.add(pattern);
}