Skip to content

Commit 182c369

Browse files
fix(security): escape double quotes in esc() to prevent XSS (#3209)
The esc() function in telegram-style.ts escaped &, <, > but not double quotes. When esc() output is interpolated into HTML attribute values (e.g. href="..."), unescaped quotes allow attribute injection (XSS). - Add .replace(/"/g, '&quot;') to esc() in telegram-style.ts - Mirror fix in test helper esc() functions - Add 2 new tests: double-quote escaping and combined HTML-special chars Closes #3209 CodeQL: security/code-scanning/142
1 parent 449abb0 commit 182c369

3 files changed

Lines changed: 12 additions & 3 deletions

File tree

src/__tests__/telegram-formatting.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { describe, it, expect } from 'vitest';
77
// Test the formatting logic directly (these mirror the internal functions)
88

99
function esc(text: string): string {
10-
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
10+
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1111
}
1212

1313
function truncate(text: string, maxLen: number): string {
@@ -164,6 +164,14 @@ describe('Telegram formatting (Issue #43)', () => {
164164
it('should handle empty string', () => {
165165
expect(esc('')).toBe('');
166166
});
167+
168+
it('should escape double quotes to prevent attribute injection', () => {
169+
expect(esc('hello "world"')).toBe('hello &quot;world&quot;');
170+
});
171+
172+
it('should escape all HTML-special characters together', () => {
173+
expect(esc('<a href="x">&')).toBe('&lt;a href=&quot;x&quot;&gt;&amp;');
174+
});
167175
});
168176

169177
describe('Path shortening', () => {

src/__tests__/telegram-style.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { describe, it, expect } from 'vitest';
1313

1414
// Re-implement formatting functions for testing (mirrors telegram.ts)
1515
function esc(text: string): string {
16-
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
16+
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1717
}
1818

1919
function truncate(text: string, maxLen: number): string {

src/channels/telegram-style.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export function esc(text: string): string {
1919
return text
2020
.replace(/&/g, '&amp;')
2121
.replace(/</g, '&lt;')
22-
.replace(/>/g, '&gt;');
22+
.replace(/>/g, '&gt;')
23+
.replace(/"/g, '&quot;');
2324
}
2425

2526
export function bold(text: string): string {

0 commit comments

Comments
 (0)