Skip to content

๐Ÿ›ก๏ธ Sentinel: [๋ณด์•ˆ ๊ฐœ์„ ] ๋ฉ”์ธ ํŽ˜์ด์ง€ CSP ๊ฐ•ํ™” ๋ฐ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ - #97

Merged
opencode-agent[bot] merged 2 commits into
mainfrom
sentinel-strict-csp-main-10918979539190325931
Aug 3, 2026
Merged

๐Ÿ›ก๏ธ Sentinel: [๋ณด์•ˆ ๊ฐœ์„ ] ๋ฉ”์ธ ํŽ˜์ด์ง€ CSP ๊ฐ•ํ™” ๋ฐ ๊ฒ€์ฆ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€#97
opencode-agent[bot] merged 2 commits into
mainfrom
sentinel-strict-csp-main-10918979539190325931

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

๐Ÿšจ Severity: HIGH
๐Ÿ’ก Vulnerability: ๋ฉ”์ธ index.html์ด ๋А์Šจํ•œ default-src 'self' CSP์™€ base-uri 'self'๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด, ์—„๊ฒฉํ•œ ๊ฑฐ๋ถ€ ๊ธฐ๋ณธ(deny-by-default) ์ ‘๊ทผ ๋ฐฉ์‹๋ณด๋‹ค ์ทจ์•ฝํ–ˆ์Šต๋‹ˆ๋‹ค. ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋™์  ์ฝ˜ํ…์ธ ๊ฐ€ ์ถ”ํ›„ ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด ๋„“์€ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.
๐ŸŽฏ Impact: ํ–ฅํ›„ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ DOM ์‹ฑํฌ๊ฐ€ ๋„์ž…๋˜๊ฑฐ๋‚˜ ์„œ๋“œํŒŒํ‹ฐ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํ›ผ์†๋  ๊ฒฝ์šฐ, XSS๋‚˜ ๋ฐ์ดํ„ฐ ์ฃผ์ž… ๊ณต๊ฒฉ์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ”ง Fix: index.html์˜ CSP๋ฅผ default-src 'none'์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ํ•„์š”ํ•œ ์ž์‚ฐ๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉ(script-src 'self', style-src 'self' ๋“ฑ)ํ•˜๋„๋ก ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ base-uri์™€ object-src๋ฅผ 'none'์œผ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
โœ… Verification: ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์œ ์ง€ํ•˜๊ณ  ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด tests/test_index_security.py ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๊ฐ€ ๋ชจ๋‘ ์ •์ƒ ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค.


PR created automatically by Jules for task 10918979539190325931 started by @seonghobae

๋ฉ”์ธ ํŽ˜์ด์ง€(`index.html`)์˜ Content-Security-Policy๋ฅผ `default-src 'none'` ๊ธฐ๋ฐ˜์˜ ์—„๊ฒฉํ•œ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹์œผ๋กœ ๊ฐ•ํ™”ํ•˜์—ฌ ์ž ์žฌ์ ์ธ ๊ณต๊ฒฉ ํ‘œ๋ฉด์„ ์ตœ์†Œํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ฒ€์ฆํ•˜๋Š” `test_index_security.py` ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
@google-labs-jules

Copy link
Copy Markdown

๐Ÿ‘‹ Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a ๐Ÿ‘€ emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings July 21, 2026 14:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the static siteโ€™s main entrypoint (index.html) by switching to a strict deny-by-default Content Security Policy (CSP) and adding Python regression tests to prevent future CSP loosening or inline active-content regressions.

Changes:

  • Strengthen index.html CSP to default-src 'none' with explicit allowlists for required asset types and stronger restrictions (base-uri 'none', frame-src 'none', Trusted Types enforcement).
  • Add tests/test_index_security.py to assert the strict CSP is present and that no inline <style>, inline <script>, style=, or on*= handlers exist.
  • Document the security change in CHANGELOG.md and record the security learning in .jules/sentinel.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
index.html Replaces permissive CSP with a strict allowlist CSP suitable for a static GitHub Pages site.
tests/test_index_security.py Adds regression tests that enforce strict CSP presence and absence of inline active content.
CHANGELOG.md Notes the CSP hardening under [Unreleased] for user-facing security changes.
.jules/sentinel.md Captures the CSP hardening lesson to prevent future regressions.

๐Ÿ’ก Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@opencode-agent[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
โš™๏ธ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 652e34bc-c8f5-423b-95bc-56c8117a7955

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 96493a6 and 0c6088a.

๐Ÿ“’ Files selected for processing (4)
  • .jules/sentinel.md
  • CHANGELOG.md
  • index.html
  • tests/test_index_security.py

Comment @coderabbitai help to get the list of available commands.

@opencode-agent

opencode-agent Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: 0c6088af47882cd0f864d1423e514a7f773c3648
  • Workflow run: 30812295708
  • Workflow attempt: 1
  • Gate result: APPROVE (exit 0)

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Test: test_index_security.py"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test: test_index_security.py"]
  R2 --> V2["targeted test run"]
Loading

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

Approval sufficiency: PR #97 (head 0c6088a) hardens index.html:6 from default-src 'self' to a strict deny-by-default policy with explicit allowlists, adds tests/test_index_security.py (62 lines, 2 tests), a sentinel learning entry, and a CHANGELOG line; changed-file evidence inspected: index.html (CSP meta hunk) and tests/test_index_security.py (full source block). Verification posture: trusted Coverage execution evidence reports Result: PASS (supported repository test suites passed); Failed GitHub Check evidence reports no completed failed checks at head; Other unresolved review thread evidence reports none. Linter/static: no repo-native lint contract for these files (only hadolint Dockerfile and trivy fs . in contracts); no lint findings reported. TDD/regression: new tests/test_index_security.py adds test_index_declares_strict_csp and test_index_has_no_inline_active_content that fail on any future CSP loosening or inline active content. Coverage: Coverage execution evidence shows supported repository test suites passed (Result: PASS). Docstring coverage: configured repository docstring gates passed or advisory per Coverage execution evidence; new module and both tests carry docstrings. DAG: compact Mermaid flowchart (base-to-head) index.html head CSP meta -> browser CSP enforcement -> allowed same-origin asset fetch (styles.css, i18n.js, images, fonts) and blocked inline/eval/frame/object content; tests/test_index_security.py -> static assertions over head bytes -> Coverage PASS. PoC/execution: no web E2E execution receipts were present; behavior established by trusted Coverage PASS plus source trace (stated source limitation). DDD/domain: no domain-model surface changed. CDD/context: change is confined to the site's existing static security posture and mirrors the shipped component-gallery strict-CSP work (#79) and sentinel log convention. Similar issues: pattern matches test_component_gallery_security.py and prior sentinel entries exactly. Claim/concept check: sentinel and CHANGELOG claims (default-src 'none', base-uri 'none', object-src 'none', explicit allowlists) match index.html:6 byte-for-byte. Standards search: CSP3 deny-by-default semantics applied; meta-delivered CSP cannot carry frame-ancestors/report-uri/sandbox, which are not needed here; require-trusted-types-for in meta matches shipped repo precedent. Compatibility/convention: no schema/API/config objects renamed; CSP directive names follow the W3C CSP grammar; no reserved-word or single-word identifier risk on any changed surface. Breaking-change/backcompat: default-src/frame-src tightening blocks resource categories previously allowed only via the 'self' fallback; all known page assets are explicitly allowed and img-src was already 'self' pre-change; no consumer contracts affected. Implementation completeness: no placeholder bodies; the new test module is fully implemented and wired to the existing tests/ convention. Performance: CSP is enforcement-only document metadata; no runtime cost. Developer experience: sentinel learning entry and CHANGELOG line keep the repo's security-audit trail current, matching sibling patterns. User experience: static site assets are unaffected under the new allowlist; no interactive surface changed. Visual/DOM: no Playwright execution receipts available; the static HTML surface was reviewed from the focused hunk and CodeGraph source blocks (stated source limitation). Accessibility/i18n: no DOM/ARIA change; lang=ko and i18n.js flow untouched. Supply-chain/license: zero dependency changes. Packaging: the new test follows the repository's pre-existing unpackaged tests/ convention (no package manifest exists repo-wide; flagged as a pre-existing signal, not introduced by this PR). Security/privacy: strict deny-by-default CSP with script-src 'self', style-src 'self', base-uri 'none', object-src 'none', frame-src 'none', form-action 'none', and require-trusted-types-for 'script'; no unsafe-inline/unsafe-eval; no identifier-exposure surface added or changed.

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including .jules/sentinel.md, CHANGELOG.md, index.html, tests/test_index_security.py.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects .jules/sentinel.md to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source claims require trusted bounded source evidence prepared outside the isolated model process; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: deterministic repair does not infer browser runtime execution; source-backed DOM/UI evidence and trusted workflow receipts were reviewed when present, and non-web surfaces used API/CLI/log/docs/workflow evidence instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

Adversarial validation

{"status":"passed","probes":[{"path":"index.html","line":6,"hypothesis":"The new deny-by-default CSP meta at index.html:6 is weaker than claimed, e.g. it still permits unsafe-inline/unsafe-eval or keeps default-src and base-uri at 'self'.","attack_or_counterexample":"A rewritten policy that keeps default-src 'self' and base-uri 'self' while only adding script-src 'self' would be a weaker-than-claimed change; check whether the head diff and the new regression tests would reject it.","evidence":"Trusted focused hunk at index.html:6 observed the exact head 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';' with no unsafe-inline or unsafe-eval present, and the trusted Coverage execution evidence reports Result: PASS for the supported repository test suites, in which test_index_declares_strict_csp asserts every strict directive substring and the absence of unsafe-inline/unsafe-eval (tests/test_index_security.py:44-46); source-line-sha256=7a6dba972f85d283660cf0f69ca0da6b2fdfdba8dfa5e5951c8c003da5c6b3ef","outcome":"falsified"},{"path":"tests/test_index_security.py","line":62,"hypothesis":"The new regression tests can still pass while index.html reintroduces inline active content, leaving the 'strict CSP remains enforceable' claim unguarded.","attack_or_counterexample":"Inject an inline <script>alert(1)</script>, a style attribute, or an on* event-handler attribute into index.html while leaving the CSP meta unchanged, then re-run the suite.","evidence":"Trusted source trace at tests/test_index_security.py:62 observed the final assertion set of test_index_has_no_inline_active_content (lines 52-57) rejecting <style> tags, style attributes, inline <script> without src, and on* event-handler attributes with AssertionError, and the trusted Coverage execution evidence reports the supported repository test suites passed at head SHA 0c6088af47882cd0f864d1423e514a7f773c3648, so the injected counterexample is absent from current head and the guard held; source-line-sha256=ff19446752c33c181ea9232a795beff15bc3feedd2a58087b3f5c33eeb62e992","outcome":"falsified"}],"residual_risk":"The full index.html body was not available in trusted evidence (external-directory read limitation), so resource categories newly tightened from the default-src 'self' fallback to 'none' (frame-src/child-src, media-src, worker-src, manifest-src, prefetch-src) were not runtime-verified against iframes/media/workers/manifest usage; all known page assets are explicitly allowed and img-src was already 'self' pre-change. Non-blocking doc nit: the appended sentinel entry is dated 2025-02-12 while sibling entries and the actual change are dated 2026, leaving the learning-log date out of chronological order. No failed checks or unresolved threads at head."}
  • Result: APPROVE
  • Reason: Strict deny-by-default CSP on index.html:6 is correct and internally consistent with the new regression tests, CHANGELOG line, and sentinel entry; trusted Coverage execution evidence reports the supported repository test suites passed; no failed checks and no unresolved review threads at head.
  • Head SHA: 0c6088af47882cd0f864d1423e514a7f773c3648
  • Workflow run: 30812295708
  • Workflow attempt: 1

@opencode-agent
opencode-agent Bot merged commit 44ea282 into main Aug 3, 2026
29 checks passed
@opencode-agent
opencode-agent Bot deleted the sentinel-strict-csp-main-10918979539190325931 branch August 3, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants