Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

339 lines
13 KiB
Python

"""
XSS (Cross-Site Scripting) Prevention Tests
Tests that verify user inputs are properly escaped and sanitized
to prevent XSS attacks in web templates and API responses.
"""
import pytest
import json
from tests.test_utils import add_src_to_path
add_src_to_path()
class TestXSSPrevention:
"""Test XSS prevention in web interface and API responses."""
@pytest.fixture
def flask_app(self):
"""Create a test Flask app instance."""
from local_deep_research.web.app import create_app
app, _ = create_app() # Unpack tuple (app, socket_service)
app.config["TESTING"] = True
app.config["WTF_CSRF_ENABLED"] = False # Disable CSRF for testing
return app
@pytest.fixture
def client(self, flask_app):
"""Create a test client."""
return flask_app.test_client()
def test_jinja2_autoescaping_enabled(self, flask_app):
"""Test that Jinja2 auto-escaping is enabled (Flask default)."""
# Flask enables auto-escaping by default for HTML templates
# autoescape is a function (select_jinja_autoescape) or True, not False/None
assert flask_app.jinja_env.autoescape
assert (
callable(flask_app.jinja_env.autoescape)
or flask_app.jinja_env.autoescape is True
)
def test_html_injection_in_templates(self, flask_app):
"""Test that HTML/JavaScript is escaped in templates."""
with flask_app.app_context():
from flask import render_template_string
# Malicious inputs that should be escaped
xss_payloads = [
"<script>alert('XSS')</script>",
"<img src=x onerror=alert('XSS')>",
"<svg onload=alert('XSS')>",
"javascript:alert('XSS')",
"<iframe src='javascript:alert(\"XSS\")'></iframe>",
"<body onload=alert('XSS')>",
"<input onfocus=alert('XSS') autofocus>",
]
template = "{{ user_input }}"
for payload in xss_payloads:
rendered = render_template_string(template, user_input=payload)
# Check that dangerous characters are escaped
assert (
"&lt;" in rendered
or "&gt;" in rendered
or payload not in rendered
)
# Should not contain executable script tags
assert "<script>" not in rendered.lower()
def test_json_response_escaping(self, client):
"""Test that JSON API responses properly escape HTML/JavaScript."""
# Test API endpoints that return user-generated content
xss_payloads = {
"query": "<script>alert('XSS')</script>",
"title": "<img src=x onerror=alert('XSS')>",
"content": "javascript:alert('XSS')",
}
# Python's json.dumps() doesn't escape < and > by default (unlike JavaScript)
# However, JSON is safe from XSS when:
# 1. Served with application/json content-type (browser won't execute as HTML)
# 2. Parsed as JSON first before being inserted into DOM
# 3. When inserted into HTML, Jinja2 auto-escaping handles it
for key, payload in xss_payloads.items():
json_str = json.dumps({key: payload})
# Verify JSON is valid and can be safely parsed
parsed = json.loads(json_str)
assert parsed[key] == payload # Data preserved correctly
# When JSON is rendered in HTML template, Jinja2 will escape it
# This test verifies JSON encoding works correctly
def test_research_query_xss_prevention(self, client):
"""Test that research queries containing XSS are handled safely."""
malicious_query = "<script>alert(document.cookie)</script>"
# Attempt to submit malicious query
response = client.post(
"/api/v1/research",
json={"query": malicious_query},
content_type="application/json",
)
# Response should be JSON with escaped content
if response.status_code == 200:
data = response.get_json()
# If query is echoed back, it should be escaped
if "query" in data:
assert "<script>" not in data["query"] or "\u003c" in str(data)
def test_markdown_rendering_xss_prevention(self):
"""Document that Markdown requires additional sanitization for XSS prevention."""
# CRITICAL SECURITY NOTE:
# The standard markdown library provides NO XSS protection by default.
# It passes through HTML and javascript: URLs as-is.
#
# Applications MUST use additional sanitization layers:
# 1. bleach.clean() to sanitize HTML output
# 2. bleach.linkify() with allowed_protocols=['http', 'https', 'mailto']
# 3. Content Security Policy headers to block inline scripts
# 4. Jinja2 auto-escaping when rendering markdown output in templates
try:
import markdown
md = markdown.Markdown(extensions=["extra", "codehilite"])
# Demonstrate that markdown passes through dangerous HTML
dangerous_samples = {
"script_tag": "<script>alert('XSS')</script>",
"onerror": "<img src=x onerror=alert('XSS')>",
"javascript_link": "[Click](javascript:alert('XSS'))",
}
for name, sample in dangerous_samples.items():
_rendered = md.convert(sample)
# Markdown does NOT sanitize these - they remain dangerous
# Applications must sanitize the output before displaying
# This test documents that markdown needs additional sanitization
# The application should use bleach or similar before displaying
# markdown-rendered content to users
assert True # Documentation test
except ImportError:
pytest.skip("markdown library not installed")
def test_url_parameter_xss(self, client):
"""Test that URL parameters are sanitized against XSS."""
xss_in_url = "<script>alert('XSS')</script>"
# Test various endpoints with malicious URL parameters
endpoints = [
f"/search?q={xss_in_url}",
f"/research/{xss_in_url}",
]
for endpoint in endpoints:
response = client.get(endpoint)
# Response should escape the XSS payload
if response.status_code == 200:
html = response.get_data(as_text=True)
# Script tags should be escaped in HTML output
assert "<script>alert" not in html or "&lt;script&gt;" in html
def test_content_type_headers(self, client):
"""Test that responses have proper Content-Type headers to prevent XSS."""
response = client.get("/")
# HTML responses should have correct Content-Type
if "text/html" in response.content_type:
assert "charset" in response.content_type.lower()
# API responses should be application/json
api_response = client.get("/api/v1/health")
if api_response.status_code == 200:
assert "application/json" in api_response.content_type
def test_html_sanitization_in_research_content(self):
"""Test that research content from external sources is sanitized."""
# LDR retrieves content from web sources - this content should be sanitized
malicious_html_content = """
<h1>Legitimate Content</h1>
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<p onclick="alert('XSS')">Click me</p>
"""
try:
from bs4 import BeautifulSoup
# Simulate sanitization (remove script tags, event handlers)
soup = BeautifulSoup(malicious_html_content, "html.parser")
# Remove script tags
for script in soup.find_all("script"):
script.decompose()
# Remove event handlers from tags
for tag in soup.find_all():
for attr in list(tag.attrs):
if attr.startswith("on"): # onclick, onload, onerror, etc.
del tag.attrs[attr]
cleaned = str(soup)
# Verify dangerous elements are removed
assert "<script>" not in cleaned.lower()
assert "onerror" not in cleaned.lower()
assert "onclick" not in cleaned.lower()
except ImportError:
pytest.skip("BeautifulSoup not installed")
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
def test_dom_based_xss_prevention(self):
"""Test prevention of DOM-based XSS through JavaScript."""
# This is a documentation test for frontend security
# DOM-based XSS happens when client-side JavaScript uses untrusted data
# Common vulnerable patterns:
# - document.write(user_input)
# - element.innerHTML = user_input
# - element.outerHTML = user_input
# - eval(user_input)
# Safe alternatives:
# - element.textContent = user_input (safely escapes)
# - element.setAttribute('data-value', user_input)
# - Use framework's built-in escaping (React, Vue, etc.)
# This test documents that frontend code should:
# 1. Use textContent instead of innerHTML for user data
# 2. Never use eval() with user input
# 3. Validate and sanitize before inserting into DOM
# 4. Use Content Security Policy (CSP) headers
assert True # Documentation test
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
def test_stored_xss_prevention(self):
"""
Test that stored XSS (persistent XSS) is prevented.
User-submitted content stored in database should be sanitized before display.
"""
# Stored XSS workflow:
# 1. Attacker submits malicious content (e.g., research query with XSS)
# 2. Content is stored in database
# 3. Content is displayed to other users
# 4. XSS executes in victim's browser
# Prevention measures:
# 1. Escape output when rendering (Jinja2 auto-escape)
# 2. Sanitize input before storage (remove dangerous HTML)
# 3. Use Content Security Policy to block inline scripts
# 4. Validate content type before rendering
# This test documents our XSS prevention strategy
assert True # Documentation test
class TestContentSecurityPolicy:
"""Test Content Security Policy (CSP) headers."""
@pytest.fixture
def client(self):
"""Create a test client."""
from local_deep_research.web.app import create_app
app, _ = create_app() # Unpack tuple (app, socket_service)
app.config["TESTING"] = True
return app.test_client()
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
def test_csp_headers_present(self, client):
"""Test that Content-Security-Policy headers are set (recommended)."""
client.get("/")
# Check if CSP header is present (it's a good security practice)
# Note: This test may fail if CSP is not yet implemented
# CSP headers prevent inline script execution and XSS
# Recommended CSP header:
# Content-Security-Policy: default-src 'self'; script-src 'self';
# This is a documentation test - CSP implementation is recommended
# but not critical if output escaping is properly implemented
# Uncomment when CSP is implemented:
# assert "Content-Security-Policy" in response.headers
pass # Placeholder for future CSP implementation
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
def test_xframe_options_header(self, client):
"""Test that X-Frame-Options header prevents clickjacking."""
client.get("/")
# X-Frame-Options prevents the page from being loaded in an iframe
# This prevents clickjacking attacks
# Recommended values:
# X-Frame-Options: DENY or SAMEORIGIN
# This is a recommended security header
# Uncomment when implemented:
# assert "X-Frame-Options" in response.headers
pass # Placeholder for future implementation
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
def test_xss_prevention_documentation():
"""
Documentation test explaining XSS prevention strategy in LDR.
XSS Prevention Layers:
1. Input Validation: Validate and sanitize user inputs
2. Output Escaping: Jinja2 auto-escaping (enabled by default)
3. JSON Encoding: Proper JSON serialization escapes HTML
4. HTML Sanitization: Clean HTML from external sources (BeautifulSoup)
5. CSP Headers: (Recommended) Block inline scripts
6. Safe Markdown: Sanitize markdown rendering
Primary Risk Areas for LDR:
1. Research queries (user input)
2. Research results (external content)
3. Saved reports (stored content)
4. API responses (JSON output)
Mitigation:
- Flask/Jinja2 auto-escaping handles most template XSS
- JSON responses are properly encoded
- External content should be sanitized
- No user-controlled eval() or innerHTML usage
"""
assert True # Documentation test