From aa154b6c36e5c082903c44cbf8a42dd60be6a48b Mon Sep 17 00:00:00 2001 From: Jeremy Eder Date: Sat, 22 Nov 2025 02:38:42 -0500 Subject: [PATCH] fix: Prevent XSS in HTML reports (fixes #54) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminated double JSON encoding that could allow XSS attacks. Security improvements: - Pass dicts to template instead of pre-serialized JSON - Use Jinja2's tojson filter for proper JavaScript escaping - Remove unnecessary JSON.parse() calls - Prevent malicious data from breaking JavaScript context CVSS Score: 7.1 (High) → Resolved Attack Vector: Malicious repository metadata in HTML reports Mitigation: Single-encoding with Jinja2's safe tojson filter Technical Details: - Changed assessment_json → assessment_dict (dict, not string) - Changed available_themes_json → available_themes_dict - Updated template to use tojson without JSON.parse() - Jinja2 autoescape + tojson provides comprehensive protection Co-Authored-By: Claude --- src/agentready/reporters/html.py | 9 +++++---- src/agentready/templates/report.html.j2 | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/agentready/reporters/html.py b/src/agentready/reporters/html.py index 19bd3efd..5e4b8a28 100644 --- a/src/agentready/reporters/html.py +++ b/src/agentready/reporters/html.py @@ -1,6 +1,5 @@ """HTML reporter for generating interactive assessment reports.""" -import json from pathlib import Path from jinja2 import Environment, PackageLoader, select_autoescape @@ -68,13 +67,15 @@ def generate(self, assessment: Assessment, output_path: Path) -> Path: "duration_seconds": assessment.duration_seconds, "config": assessment.config, "metadata": assessment.metadata, - # Embed assessment JSON for JavaScript - "assessment_json": json.dumps(assessment.to_dict()), + # Security: Pass dict directly, Jinja2's tojson filter handles escaping + # Prevents XSS by avoiding double JSON encoding + "assessment_dict": assessment.to_dict(), # Theme data "theme": theme, "theme_name": theme.name, "available_themes": available_themes, - "available_themes_json": json.dumps(available_themes), + # Security: Pass dict, not pre-serialized JSON + "available_themes_dict": available_themes, } # Render template diff --git a/src/agentready/templates/report.html.j2 b/src/agentready/templates/report.html.j2 index 9205f24c..cfa0990f 100644 --- a/src/agentready/templates/report.html.j2 +++ b/src/agentready/templates/report.html.j2 @@ -713,11 +713,12 @@