fix(security): unify secret redaction in public comment outputs (#1693)

Ensure all public issue, PR, and inline comments apply redactSecrets() in addition to sanitizeContent() before submitting payloads to the GitHub API. This aligns public comment output with error log and step-summary redaction policies, preventing potential leakage of Anthropic API keys, AWS credentials, Slack tokens, JWTs, and GitHub tokens.
This commit is contained in:
Juwan
2026-08-18 17:23:11 -07:00
committed by GitHub
parent d40ddef4c0
commit 54eadc2f72
5 changed files with 96 additions and 6 deletions
+64
View File
@@ -0,0 +1,64 @@
import { describe, expect, it } from "bun:test";
import { redactSecrets, sanitizeContent } from "../src/github/utils/sanitizer";
describe("Public Comment Output Sanitization & Redaction", () => {
it("redacts all credential types from public comment output", () => {
const rawComment = [
"Here is the summary of the work done:",
"- GitHub Token: ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"- Anthropic Key: sk-ant-api03-abcdefghijklmnopqrstuvwxyz1234567890",
"- AWS Access Key: AKIAIOSFODNN7EXAMPLE",
"- Slack Bot Token: xoxb-1234567890-abcdefghijkl-mnopqrstuvwx",
"- JWT Bearer: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
"<!-- Hidden instruction injection -->",
"Invisible\u200Bzero-width chars",
"![Image Alt Injection](https://example.com/pic.png)",
].join("\n");
const sanitizedOutput = redactSecrets(sanitizeContent(rawComment));
// Ensure all secret types are redacted
expect(sanitizedOutput).not.toContain(
"ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
);
expect(sanitizedOutput).not.toContain(
"sk-ant-api03-abcdefghijklmnopqrstuvwxyz1234567890",
);
expect(sanitizedOutput).not.toContain("AKIAIOSFODNN7EXAMPLE");
expect(sanitizedOutput).not.toContain(
"xoxb-1234567890-abcdefghijkl-mnopqrstuvwx",
);
expect(sanitizedOutput).not.toContain(
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
);
expect(sanitizedOutput).toContain("[REDACTED_GITHUB_TOKEN]");
expect(sanitizedOutput).toContain("[REDACTED_ANTHROPIC_KEY]");
expect(sanitizedOutput).toContain("[REDACTED_AWS_KEY_ID]");
expect(sanitizedOutput).toContain("[REDACTED_SLACK_TOKEN]");
expect(sanitizedOutput).toContain("[REDACTED_JWT]");
// Ensure prompt injection / invisible chars / hidden tags are also sanitized
expect(sanitizedOutput).not.toContain(
"<!-- Hidden instruction injection -->",
);
expect(sanitizedOutput).not.toContain("\u200B");
expect(sanitizedOutput).not.toContain("Image Alt Injection");
expect(sanitizedOutput).toContain("![](https://example.com/pic.png)");
});
it("ensures public comments have the same secret redaction coverage as logs/errors", () => {
const errorDetails =
"Error: failed to connect with sk-ant-abcdefghijklmnopqrstuvwxyz123456 and AKIAIOSFODNN7EXAMPLE";
const commentBody =
"Report: encountered sk-ant-abcdefghijklmnopqrstuvwxyz123456 and AKIAIOSFODNN7EXAMPLE";
const redactedError = redactSecrets(errorDetails);
const redactedComment = redactSecrets(sanitizeContent(commentBody));
expect(redactedError).toContain("[REDACTED_ANTHROPIC_KEY]");
expect(redactedError).toContain("[REDACTED_AWS_KEY_ID]");
expect(redactedComment).toContain("[REDACTED_ANTHROPIC_KEY]");
expect(redactedComment).toContain("[REDACTED_AWS_KEY_ID]");
});
});