Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Gvisual/src/gvisual/CentralityRadarExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ public String exportToString() {
}

private String escapeJson(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"")
.replace("\n", "\\n").replace("\r", "\\r");
return HtmlExportUtils.escapeJs(s);
}

private String buildHtml(String nodesJson, int totalNodes) {
Expand Down
5 changes: 1 addition & 4 deletions Gvisual/src/gvisual/GraphAlgorithmAnimator.java
Original file line number Diff line number Diff line change
Expand Up @@ -830,10 +830,7 @@ private static String escapeXml(String s) {
}

private static String escapeJS(String s) {
return "\"" + s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "") + "\"";
return "\"" + HtmlExportUtils.escapeJs(s) + "\"";
}

// Union-Find for Kruskal
Expand Down
21 changes: 20 additions & 1 deletion Gvisual/src/gvisual/GraphDiffHtmlExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,26 @@ private static String escapeHtml(String s) {
return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;");
}

/**
* Escapes a string for safe embedding inside a JavaScript double-quoted
* string literal within an HTML {@code <script>} block.
*
* <p>Handles: backslash, double-quote, newlines, forward-slash (prevents
* {@code </script>} injection — CWE-79), backtick and {@code $} (prevents
* template literal injection), and Unicode line/paragraph separators
* (U+2028/U+2029) which are valid in JSON but break JS string literals.</p>
*/
private static String escapeJs(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "");
if (s == null) return "";
return s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("'", "\\'")
.replace("/", "\\/") // prevent </script> breakout
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("`", "\\`") // prevent template literal injection
.replace("$", "\\$") // prevent ${} interpolation
.replace("\u2028", "\\u2028") // Unicode line separator
.replace("\u2029", "\\u2029"); // Unicode paragraph separator
}
}
3 changes: 1 addition & 2 deletions Gvisual/src/gvisual/GraphTimelineExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,7 @@ private String mapToJson(Map<String, ?> map, boolean dummy) {
}

private static String escapeJson(String s) {
return s.replace("\\", "\\\\").replace("\"", "\\\"")
.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
return HtmlExportUtils.escapeJs(s);
}

private static String escapeHtml(String s) {
Expand Down
62 changes: 62 additions & 0 deletions Gvisual/src/gvisual/HtmlExportUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gvisual;

/**
* Shared HTML/JavaScript escaping utilities for file exporters.
*
* <p>Provides secure string escaping to prevent XSS (CWE-79) when
* embedding user-controlled data (node IDs, labels, titles) in
* generated HTML and JavaScript output.</p>
*
* @author zalenix
*/
public final class HtmlExportUtils {

private HtmlExportUtils() { /* utility class */ }

/**
* Escapes a string for safe embedding inside a JavaScript double-quoted
* string literal within an HTML {@code <script>} block.
*
* <p>Handles:</p>
* <ul>
* <li>Backslash, double-quote, single-quote</li>
* <li>Forward-slash — prevents {@code </script>} tag injection (CWE-79)</li>
* <li>Newline and carriage return</li>
* <li>Backtick and {@code $} — prevents template literal injection</li>
* <li>Unicode line/paragraph separators (U+2028, U+2029) — valid in
* JSON but break JavaScript string literals in older engines</li>
* </ul>
*
* @param s the string to escape (null-safe, returns empty string for null)
* @return escaped string safe for JS string literal embedding
*/
public static String escapeJs(String s) {
if (s == null) return "";
return s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("'", "\\'")
.replace("/", "\\/") // prevent </script> breakout
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
.replace("`", "\\`") // prevent template literal injection
.replace("$", "\\$") // prevent ${} interpolation
.replace("\u2028", "\\u2028") // Unicode line separator
.replace("\u2029", "\\u2029"); // Unicode paragraph separator
}

/**
* Escapes a string for safe embedding in HTML content.
*
* @param s the string to escape (null-safe)
* @return HTML-escaped string
*/
public static String escapeHtml(String s) {
if (s == null) return "";
return s.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
.replace("'", "&#x27;");
}
}
Loading