From 0f97e7c37d44abfa4ddfddf44a3290fdad586034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matth=C3=A4us=20G=2E=20Chajdas?= Date: Thu, 26 Mar 2026 20:16:41 +0100 Subject: [PATCH] Harden the HTML formatter against CSS. Escape various text-only attributes using `html.escape`. --- pygments/formatters/html.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pygments/formatters/html.py b/pygments/formatters/html.py index 7174ad2dd7..17e6741452 100644 --- a/pygments/formatters/html.py +++ b/pygments/formatters/html.py @@ -18,6 +18,8 @@ from pygments.token import Token, Text, STANDARD_TYPES from pygments.util import get_bool_opt, get_int_opt, get_list_opt +import html + try: import ctags except ImportError: @@ -422,14 +424,14 @@ def __init__(self, **options): self.nowrap = get_bool_opt(options, 'nowrap', False) self.noclasses = get_bool_opt(options, 'noclasses', False) self.classprefix = options.get('classprefix', '') - self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight')) - self.cssstyles = self._decodeifneeded(options.get('cssstyles', '')) + self.cssclass = html.escape(self._decodeifneeded(options.get('cssclass', 'highlight'))) + self.cssstyles = html.escape(self._decodeifneeded(options.get('cssstyles', ''))) self.prestyles = self._decodeifneeded(options.get('prestyles', '')) self.cssfile = self._decodeifneeded(options.get('cssfile', '')) self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False) self.tagsfile = self._decodeifneeded(options.get('tagsfile', '')) self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', '')) - self.filename = self._decodeifneeded(options.get('filename', '')) + self.filename = html.escape(self._decodeifneeded(options.get('filename', ''))) self.wrapcode = get_bool_opt(options, 'wrapcode', False) self.span_element_openers = {} self.debug_token_types = get_bool_opt(options, 'debug_token_types', False) @@ -452,9 +454,9 @@ def __init__(self, **options): self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0)) self.nobackground = get_bool_opt(options, 'nobackground', False) - self.lineseparator = options.get('lineseparator', '\n') - self.lineanchors = options.get('lineanchors', '') - self.linespans = options.get('linespans', '') + self.lineseparator = html.escape(options.get('lineseparator', '\n')) + self.lineanchors = html.escape(options.get('lineanchors', '')) + self.linespans = html.escape(options.get('linespans', '')) self.anchorlinenos = get_bool_opt(options, 'anchorlinenos', False) self.hl_lines = set() for lineno in get_list_opt(options, 'hl_lines', []):