diff --git a/__tests__/integration/ai-review.test.js b/__tests__/integration/ai-review.test.js
index c792031..1e1c803 100644
--- a/__tests__/integration/ai-review.test.js
+++ b/__tests__/integration/ai-review.test.js
@@ -387,12 +387,42 @@ describe('ai-review', () => {
expect(result).toContain('advisory only');
});
- it('sanitizes the AI response', () => {
+ it('sanitizes workflow commands in the AI response', () => {
const result = formatReviewComment('Good code\n::set-output name=x::hack', 10);
expect(result).toContain('[sanitized command]');
expect(result).not.toContain('::set-output');
});
+ // Bug #29 — widen sanitiser
+ it('escapes HTML angle brackets so injected
/ ',
+ 11
+ );
+ expect(result).not.toMatch(/
{
+ const result = formatReviewComment(
+ 'cc @octocat please review, also @pulseengine/maintainers',
+ 12
+ );
+ // The @ remains visible to humans but the username is preceded by a
+ // zero-width space (\u200B), preventing GitHub from creating a mention.
+ expect(result).toContain('@\u200Boctocat');
+ expect(result).toContain('@\u200Bpulseengine/maintainers');
+ expect(result).not.toMatch(/(? {
+ // `foo@example.com` is not a GitHub username pattern; let it through.
+ const result = formatReviewComment('Contact foo@example.com', 13);
+ expect(result).toContain('foo');
+ });
+
it('includes local AI model attribution', () => {
const result = formatReviewComment('Review text', 1);
expect(result).toContain('local AI model');
diff --git a/src/ai-review.js b/src/ai-review.js
index ea12e4f..30dd3d2 100644
--- a/src/ai-review.js
+++ b/src/ai-review.js
@@ -65,9 +65,41 @@ function isLocalEndpoint(endpoint) {
}
}
+/**
+ * Strip patterns that an attacker-influenced PR diff could exploit through
+ * the AI model's output. Wave-1 LLM and Security agents flagged the
+ * previous one-pattern version (workflow-commands only) as too narrow —
+ * Bug #29 in `docs/agent-fleet/bugs.md`.
+ *
+ * Concretely, attacker patterns we now neutralise:
+ *
+ * 1. GitHub Actions workflow commands (`::set-output ::`, `::error ::`)
+ * — could escape into a runner that consumes bot comments.
+ * 2. HTML elements that GitHub renders inside Markdown comments —
+ * `
`, `