Skip to content
Open
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
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@
**Vulnerability:** Missing input validation on `setLanguage()` could allow invalid strings (like Prototype Pollution payloads or arbitrary text) to be applied to the DOM (`lang` attribute) and stored in `localStorage`.
**Learning:** The global `setLanguage` function assumed inputs would only come from predefined button clicks, skipping runtime validation.
**Prevention:** Always sanitize and validate function arguments at the application boundary, even if the primary caller is trusted, to enforce defense in depth.
## 2026-07-20 - Enforce strict default-src 'none' CSP on index.html
**Vulnerability:** Weak CSP utilizing `default-src 'self'` could inadvertently allow loading unexpected resource types if they share the same origin, potentially widening the attack surface.
**Learning:** It is more secure to use an explicit allowlist approach (`default-src 'none'`) and explicitly grant `self` only to required resource types (script, style, img, font, connect).
**Prevention:** Always default to `default-src 'none'` and explicitly add directives for what is strictly needed, rather than relying on an implicitly broad `default-src 'self'`.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self'; object-src 'none'; base-uri 'self'; form-action 'none'; upgrade-insecure-requests; require-trusted-types-for 'script';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; upgrade-insecure-requests; require-trusted-types-for 'script';">
<meta name="referrer" content="strict-origin-when-cross-origin">
<title>๋งฅ๋ฝ์ง€ํ˜œ ์—ฐ๊ตฌ์‹ค | Contextual Wisdom Lab</title>
<meta
Expand Down
47 changes: 47 additions & 0 deletions tests/test_index_security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Security tests for the main index.html."""

from __future__ import annotations

import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
INDEX = ROOT / "index.html"


def _index_html() -> str:
"""Return the index HTML source."""
return INDEX.read_text(encoding="utf-8")


def _csp_content(html: str) -> str:
"""Extract the CSP meta policy from the index HTML."""
match = re.search(
r'<meta\s+http-equiv="Content-Security-Policy"\s+content="([^"]+)"',
html,
)
assert match is not None, "index must declare a CSP meta policy"
return match.group(1)


def test_index_declares_strict_csp() -> None:
"""The main site limits active content to strict whitelist."""
policy = _csp_content(_index_html())

for directive in (
"default-src 'none'",
"script-src 'self'",
"style-src 'self'",
"img-src 'self'",
"font-src 'self'",
"connect-src 'self'",
"object-src 'none'",
"base-uri 'none'",
"form-action 'none'",
"frame-src 'none'",
"upgrade-insecure-requests",
"require-trusted-types-for 'script'",
):
assert directive in policy, f"Missing {directive} in CSP"
assert "'unsafe-inline'" not in policy
assert "'unsafe-eval'" not in policy
Loading