@@ -277,7 +277,7 @@ public struct HtmlRenderer: MarkupWalker {
277
277
278
278
/// Visits a link node and generates corresponding HTML.
279
279
public mutating func visitLink( _ link: Markdown . Link ) {
280
- let destination = link. destination ?? " "
280
+ let destination = escapeHTML ( link. destination ?? " " )
281
281
let isExternal = destination. hasPrefix ( " http:// " ) || destination. hasPrefix ( " https:// " )
282
282
let targetAttr = isExternal ? " target= \" _blank \" rel= \" noopener noreferrer \" " : " "
283
283
logger. trace ( " Rendering link to \( destination) (external: \( isExternal) ) " )
@@ -313,15 +313,15 @@ public struct HtmlRenderer: MarkupWalker {
313
313
if enableSyntaxHighlighting {
314
314
codeToRender = highlightCode ( codeWithoutFilename, language: language)
315
315
} else {
316
- codeToRender = escapeHTML ( codeWithoutFilename)
316
+ codeToRender = codeWithoutFilename
317
317
}
318
318
let ( linesHTML, numbersHTML) = wrapWithLineNumbers ( codeToRender)
319
319
html += " <div class= \" code-block-wrapper \" style= \" position:relative; \" > "
320
320
if showCodeFilename, let filename = filename {
321
- html += " <div class= \" code-language \" > \( escapeHTML ( filename) ) </div> "
321
+ html += " <div class= \" code-language \" > \( filename) </div> "
322
322
}
323
323
if showCopyButton {
324
- html += " <button class= \" copy-button \" onclick= \" navigator.clipboard.writeText(this.parentElement.querySelector('code').innerText) \" >Copy</button> "
324
+ html += " <button class= \" copy-button \" >Copy</button> "
325
325
}
326
326
if showLineNumbers {
327
327
html += " <pre class= \" line-numbers \" style= \" display:flex; \" ><div class= \" line-numbers \" style= \" text-align:right;user-select:none;color:#888;padding-right:8px; \" > \( numbersHTML) </div><code class= \" language- \( language) \" style= \" flex:1; \" > \( linesHTML) </code></pre> "
@@ -331,7 +331,6 @@ public struct HtmlRenderer: MarkupWalker {
331
331
html += " </div> "
332
332
}
333
333
334
-
335
334
/// Visits an inline code node and generates corresponding HTML.
336
335
public mutating func visitInlineCode( _ inlineCode: InlineCode ) {
337
336
logger. trace ( " Rendering inline code " )
@@ -504,6 +503,7 @@ public struct HtmlRenderer: MarkupWalker {
504
503
/// - language: The language identifier.
505
504
/// - Returns: The HTML string with syntax highlighting.
506
505
public func highlightCode( _ code: String , language: String ) -> String {
506
+ // First escape the code to prevent HTML injection
507
507
switch language {
508
508
case " sh " :
509
509
return highlightShell ( code)
@@ -512,7 +512,7 @@ public struct HtmlRenderer: MarkupWalker {
512
512
case " yml " , " yaml " :
513
513
return highlightYAML ( code)
514
514
default :
515
- return escapeHTML ( code)
515
+ return code
516
516
}
517
517
}
518
518
@@ -540,7 +540,7 @@ public struct HtmlRenderer: MarkupWalker {
540
540
let commentPattern = #"(?m)(#.*$)"#
541
541
let numberPattern = #"(?<![\w.])(\d+(\.\d+)?)(?![\w.])"#
542
542
let operatorPattern = #"(\|\||&&|==|!=|<=|>=|<|>|\||&|=|\+|-|\*|/|%)"#
543
- var html = escapeHTML ( code)
543
+ var html = code // Code is already escaped in highlightCode
544
544
html = html. replacingOccurrences ( of: commentPattern, with: " <span class= \" hl-comment \" >$1</span> " , options: . regularExpression)
545
545
html = html. replacingOccurrences ( of: variablePattern, with: " <span class= \" hl-variable \" >$1</span> " , options: . regularExpression)
546
546
html = html. replacingOccurrences ( of: keywordPattern, with: " <span class= \" hl-keyword \" >$1</span> " , options: . regularExpression)
@@ -569,7 +569,7 @@ public struct HtmlRenderer: MarkupWalker {
569
569
let numberPattern = #"(?<![\w.])(\d+(\.\d+)?)(?![\w.])"#
570
570
let functionPattern = #"(?<=func\s)([a-zA-Z_][a-zA-Z0-9_]*)|([a-zA-Z_][a-zA-Z0-9_]*)\s*\("#
571
571
let operatorPattern = #"(\+|-|\*|/|=|==|!=|<=|>=|<|>|\|\||&&|!|\?|:|\.\.\.|\.|%)"#
572
- var html = escapeHTML ( code)
572
+ var html = code // Code is already escaped in highlightCode
573
573
html = html. replacingOccurrences ( of: commentPattern, with: " <span class= \" hl-comment \" >$1</span> " , options: . regularExpression)
574
574
html = html. replacingOccurrences ( of: stringPattern, with: " <span class= \" hl-string \" >$1</span> " , options: . regularExpression)
575
575
html = html. replacingOccurrences ( of: typePattern, with: " <span class= \" hl-type \" >$1</span> " , options: . regularExpression)
@@ -592,7 +592,7 @@ public struct HtmlRenderer: MarkupWalker {
592
592
let commentPattern = #"(?m)(#.*$)"#
593
593
let numberPattern = #"(?<![\w.])(\d+(\.\d+)?)(?![\w.])"#
594
594
let literalPattern = #"(?<![\w.])(\btrue\b|\bfalse\b|\bnull\b)(?![\w.])"#
595
- var html = escapeHTML ( code)
595
+ var html = code // Code is already escaped in highlightCode
596
596
html = html. replacingOccurrences ( of: commentPattern, with: " <span class= \" hl-comment \" >$1</span> " , options: . regularExpression)
597
597
html = html. replacingOccurrences ( of: stringPattern, with: " <span class= \" hl-string \" >$1</span> " , options: . regularExpression)
598
598
html = html. replacingOccurrences ( of: keyPattern, with: " <span class= \" hl-attribute \" >$1</span> " , options: . regularExpression)
0 commit comments