Skip to content

Commit e7d24ff

Browse files
authored
Merge pull request #161 from contentstack/fix/DX-5718
fix(5718): resolve security vulnerabilities in test report generator
2 parents 30bf6ff + 85df6b3 commit e7d24ff

2 files changed

Lines changed: 18 additions & 55 deletions

File tree

Scripts/generate_integration_test_report.py

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
Parses TRX (results) + Cobertura (coverage) + Structured StdOut (HTTP, assertions, context)
55
into a single interactive HTML report.
66
7-
SECURITY ENHANCEMENTS:
7+
SECURITY FEATURES:
88
- Uses defusedxml for secure XML parsing to prevent XXE attacks
9-
- Robust path traversal prevention for all file operations
9+
- Robust path traversal prevention for all file operations
1010
- Input validation and sanitization for all user-provided paths
11-
- Safe handling of external entity resolution in XML processing
11+
- No insecure XML parsing fallbacks (security-first approach)
1212
13-
Dependencies:
14-
- defusedxml (optional but recommended for security)
15-
- Python 3.7+ for optimal security features
13+
Requirements:
14+
- defusedxml>=0.7.1 (REQUIRED for secure XML parsing)
15+
- Python 3.7+ recommended
1616
"""
1717

1818
import xml.etree.ElementTree as ET
@@ -23,44 +23,17 @@
2323
import argparse
2424
from datetime import datetime
2525

26-
# Try to import defusedxml for safer XML parsing
26+
# Import defusedxml for secure XML parsing (required dependency)
2727
try:
2828
import defusedxml.ElementTree as SafeET
2929
DEFUSED_XML_AVAILABLE = True
30-
except ImportError:
31-
SafeET = None
32-
DEFUSED_XML_AVAILABLE = False
30+
except ImportError as e:
31+
print("ERROR: defusedxml is required for secure XML parsing.")
32+
print("Install it with: pip install defusedxml")
33+
print("This prevents XXE vulnerabilities in XML processing.")
34+
sys.exit(1)
3335

3436

35-
def _make_xml_parser():
36-
"""
37-
Create a hardened XML parser that prevents XXE and other XML-based attacks.
38-
Uses defusedxml for safer XML parsing when available.
39-
"""
40-
if DEFUSED_XML_AVAILABLE:
41-
return None # defusedxml uses its own parser
42-
43-
# Fallback to standard parser with security restrictions
44-
parser = ET.XMLParser()
45-
46-
# For Python 3.8+, disable resolve_entities
47-
if sys.version_info >= (3, 8):
48-
try:
49-
parser = ET.XMLParser(resolve_entities=False)
50-
except TypeError:
51-
pass
52-
53-
# Additional hardening for older versions
54-
if hasattr(parser, 'parser'):
55-
try:
56-
# Disable external entity processing
57-
parser.parser.DefaultHandler = lambda data: None
58-
parser.parser.ExternalEntityRefHandler = lambda *args: False
59-
parser.parser.EntityDeclHandler = lambda *args: False
60-
except AttributeError:
61-
pass
62-
63-
return parser
6437

6538

6639
def _sanitize_output_path(output_path):
@@ -133,15 +106,9 @@ def __init__(self, trx_path, coverage_path=None):
133106
# ──────────────────── TRX PARSING ────────────────────
134107

135108
def parse_trx(self):
136-
# Safely parse TRX file with defusedxml when available
109+
# Safely parse TRX file with defusedxml (required for security)
137110
try:
138-
if DEFUSED_XML_AVAILABLE:
139-
tree = SafeET.parse(self.trx_path)
140-
else:
141-
# Warn about potential security risk
142-
print("Warning: defusedxml not available. Using standard XML parser with limited security mitigations.")
143-
parser = _make_xml_parser()
144-
tree = ET.parse(self.trx_path, parser=parser)
111+
tree = SafeET.parse(self.trx_path)
145112
root = tree.getroot()
146113
except Exception as e:
147114
raise ValueError(f"Failed to parse TRX file safely: {e}") from e
@@ -259,12 +226,8 @@ def parse_coverage(self):
259226
if not self.coverage_path or not os.path.exists(self.coverage_path):
260227
return
261228
try:
262-
# Safely parse coverage file with defusedxml when available
263-
if DEFUSED_XML_AVAILABLE:
264-
tree = SafeET.parse(self.coverage_path)
265-
else:
266-
parser = _make_xml_parser()
267-
tree = ET.parse(self.coverage_path, parser=parser)
229+
# Safely parse coverage file with defusedxml (required for security)
230+
tree = SafeET.parse(self.coverage_path)
268231
root = tree.getroot()
269232
self.coverage['lines_pct'] = float(root.get('line-rate', 0)) * 100
270233
self.coverage['branches_pct'] = float(root.get('branch-rate', 0)) * 100

Scripts/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
# Requirements for Scripts directory
2-
# For secure XML parsing in generate_integration_test_report.py
1+
# Required dependencies for Scripts directory
2+
# defusedxml: REQUIRED for secure XML parsing (prevents XXE vulnerabilities)
33
defusedxml>=0.7.1

0 commit comments

Comments
 (0)