Skip to content

fix: prevent PHI leakage via .gitignore and add HTTP security headers (#114, #109) - #116

Merged
Liohtml merged 4 commits into
Liohtml:mainfrom
rtmalikian:fix/phi-gitignore-and-security-headers
Jun 19, 2026
Merged

fix: prevent PHI leakage via .gitignore and add HTTP security headers (#114, #109)#116
Liohtml merged 4 commits into
Liohtml:mainfrom
rtmalikian:fix/phi-gitignore-and-security-headers

Conversation

@rtmalikian

@rtmalikian rtmalikian commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR fixes two security issues in MedCheck, an AI-powered medical imaging analysis tool that handles patient PHI:

Fix 1: PHI leakage via missing .gitignore (#114)

The CLI defaults to writing reports (JSON/PDF/HTML) to ./output/ — these reports contain full patient PHI (name, patient ID, DOB, sex, study details). The output/ directory was not listed in .gitignore, meaning git add . would silently stage PHI-containing files, and a git push to a shared remote would leak patient data.

Fix: Added output/ to .gitignore with a PHI warning comment, and updated the CLI --output help text to alert developers.

Fix 2: Missing HTTP security headers (#109)

The FastAPI web app had no security response headers — no X-Frame-Options, X-Content-Type-Options, Referrer-Policy, or Content-Security-Policy. This is a meaningful hardening gap for an app that handles patient-derived medical imaging data, especially when exposed on the network via MEDCHECK_HOST=0.0.0.0.

Fix: Added _SecurityHeadersMiddleware (using BaseHTTPMiddleware) that sets:

  • X-Frame-Options: DENY — prevents clickjacking
  • X-Content-Type-Options: nosniff — prevents MIME sniffing
  • Referrer-Policy: no-referrer — prevents patient-context URL leakage
  • Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' — restricts script/frame sources

Changes

File Change
.gitignore Add output/ with PHI warning comment
src/medcheck/main.py Update --output help text to mention PHI
src/medcheck/web/app.py Add _SecurityHeadersMiddleware class and register it
tests/unit/test_web.py Add 3 tests for security headers

Verification

$ pytest tests/ -v
============================= 134 passed in 5.16s ==============================

All 134 tests pass, including the 3 new security header tests.


About the Author: Raphael Malikian — Clinical AI Solutions Architect. I specialise in building and fixing AI/ML systems for healthcare, including vector databases, RAG pipelines, and clinical NLP. If you need help with your project or think I can add value to your organisation, feel free to reach out — I'd love to connect.

📧 rtmalikian@gmail.com
🔗 GitHub: https://github.com/rtmalikian
🔗 LinkedIn: http://www.linkedin.com/in/raphael-t-malikian-mbbs-bsc-hons-71075436a


Disclosure: This code was developed with assistance from mimo-2.5-pro (Xiaomi) via Hermes Agent (Nous Research). All changes were reviewed, tested against the actual codebase, and verified for correctness.

Summary by CodeRabbit

  • Security

    • Added HTTP security headers to all application responses, including a stricter Content-Security-Policy to prevent framing and reduce related risks.
  • Documentation

    • Updated the medcheck analyze CLI --output option description to note that generated reports may contain sensitive patient information.
    • Updated ignore rules to exclude generated report output files.
  • Tests

    • Added/extended unit tests to verify required security headers exactly match expected values on key endpoints.

Fixes Liohtml#114 — output/ directory (default for PHI-containing reports) was
not in .gitignore, risking accidental commits of patient data.

Fixes Liohtml#109 — the FastAPI web app had no security response headers,
leaving it vulnerable to clickjacking, MIME sniffing, and XSS
amplification when exposed on the network via MEDCHECK_HOST=0.0.0.0.

Changes:
- Add output/ to .gitignore with PHI warning comment
- Add _SecurityHeadersMiddleware with X-Frame-Options: DENY,
  X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer,
  and Content-Security-Policy
- Update CLI --output help text to warn about PHI
- Add 3 tests verifying security headers on health and homepage
@rtmalikian
rtmalikian requested a review from Liohtml as a code owner June 18, 2026 05:47
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 15510ba5-e127-40ea-ab44-62d168e6193d

📥 Commits

Reviewing files that changed from the base of the PR and between 72f3e15 and 46861c6.

📒 Files selected for processing (2)
  • src/medcheck/web/app.py
  • tests/unit/test_web.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/test_web.py

📝 Walkthrough

Walkthrough

The PR adds a _SecurityHeadersMiddleware Starlette middleware to the FastAPI app that injects X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Content-Security-Policy headers on every response. It also excludes the output/ directory from version control and updates the --output CLI help text with a PHI warning.

Changes

HTTP Security Headers Middleware

Layer / File(s) Summary
Middleware implementation and wiring
src/medcheck/web/app.py
Imports BaseHTTPMiddleware, defines _SecurityHeadersMiddleware with a dispatch method that appends security headers to every response, and registers it in create_app via app.add_middleware.
Security header test validation
tests/unit/test_web.py
Defines _EXPECTED_SECURITY_HEADERS constant with expected header values and adds three unit tests verifying header presence and exact values on /health and / endpoints, plus substring validation of CSP frame-ancestors directive.

PHI Data Hygiene

Layer / File(s) Summary
output/ gitignore entry and CLI PHI warning
.gitignore, src/medcheck/main.py
Adds the output/ pattern to .gitignore under a comment marking it as potentially containing patient PHI, and updates the --output/-o option help text in the analyze command to note that reports may contain patient PHI.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related issues

Poem

🐇 Hop hop, the headers are set,
No sneaky frames shall pass, I bet!
PHI tucked safe in .gitignore too,
The output/ folder? Hidden from view.
A rabbit secures what doctors trust,
Safe headers and warnings — a must! 🔒

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: preventing PHI leakage via .gitignore and adding HTTP security headers, with issue references.
Description check ✅ Passed The description is comprehensive, covering both issues, changes made, testing verification, and includes all key sections from the template with thorough detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/medcheck/web/app.py (1)

72-74: ⚡ Quick win

Mirror frame denial in the CSP.

X-Frame-Options: DENY is strong, but the CSP itself does not include frame-ancestors 'none'. Add it so modern CSP enforcement carries the same anti-framing policy, then pin the value in tests.

Proposed CSP hardening
         response.headers["Content-Security-Policy"] = (
-            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';"
+            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; "
+            "frame-ancestors 'none';"
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/medcheck/web/app.py` around lines 72 - 74, The Content-Security-Policy
header in the response.headers assignment is missing the frame-ancestors
directive. Add frame-ancestors 'none' to the CSP string to provide modern
CSP-based protection against clickjacking that matches the X-Frame-Options DENY
policy. Update any related tests to verify that the frame-ancestors 'none'
directive is present in the CSP header value.
tests/unit/test_web.py (1)

90-94: ⚡ Quick win

Pin the full CSP alongside the other expected headers.

The substring checks would still pass after widening the CSP, and they only cover /health. Put the finalized CSP value in _EXPECTED_SECURITY_HEADERS so both /health and / assert the complete policy.

Proposed test tightening
 _EXPECTED_SECURITY_HEADERS = {
     "X-Frame-Options": "DENY",
     "X-Content-Type-Options": "nosniff",
     "Referrer-Policy": "no-referrer",
+    "Content-Security-Policy": (
+        "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; "
+        "frame-ancestors 'none';"
+    ),
 }
@@
-def test_content_security_policy_present():
-    client = TestClient(create_app())
-    resp = client.get("/health")
-    csp = resp.headers.get("Content-Security-Policy", "")
-    assert "default-src 'self'" in csp
-    assert "script-src 'self'" in csp

Also applies to: 112-117

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_web.py` around lines 90 - 94, The _EXPECTED_SECURITY_HEADERS
dictionary is missing the Content-Security-Policy header. Add the full,
finalized CSP value to this dictionary alongside the existing X-Frame-Options,
X-Content-Type-Options, and Referrer-Policy headers. This ensures that both the
/health and / endpoints assert against the complete CSP policy rather than
relying on loose substring checks that could still pass if the CSP is widened.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/medcheck/web/app.py`:
- Around line 67-75: The dispatch middleware method lacks proper error handling
and test coverage. Wrap the call_next() invocation in a try/except block to
catch any exceptions, and return an explicit error response with the same
security headers applied instead of allowing exceptions to propagate—this is the
recommended best practice for BaseHTTPMiddleware. Additionally, add a test case
named test_security_headers_on_unhandled_error that verifies the security
headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and
Content-Security-Policy) are reliably present on error responses to ensure the
middleware properly hardens responses even on error paths.

---

Nitpick comments:
In `@src/medcheck/web/app.py`:
- Around line 72-74: The Content-Security-Policy header in the response.headers
assignment is missing the frame-ancestors directive. Add frame-ancestors 'none'
to the CSP string to provide modern CSP-based protection against clickjacking
that matches the X-Frame-Options DENY policy. Update any related tests to verify
that the frame-ancestors 'none' directive is present in the CSP header value.

In `@tests/unit/test_web.py`:
- Around line 90-94: The _EXPECTED_SECURITY_HEADERS dictionary is missing the
Content-Security-Policy header. Add the full, finalized CSP value to this
dictionary alongside the existing X-Frame-Options, X-Content-Type-Options, and
Referrer-Policy headers. This ensures that both the /health and / endpoints
assert against the complete CSP policy rather than relying on loose substring
checks that could still pass if the CSP is widened.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 068fc270-b4c9-4b01-a76b-70318dd13ff7

📥 Commits

Reviewing files that changed from the base of the PR and between 390467f and 72f3e15.

📒 Files selected for processing (4)
  • .gitignore
  • src/medcheck/main.py
  • src/medcheck/web/app.py
  • tests/unit/test_web.py

Comment thread src/medcheck/web/app.py
Comment on lines +67 to +75
async def dispatch(self, request: Request, call_next: Any) -> Any:
response = await call_next(request)
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["Referrer-Policy"] = "no-referrer"
response.headers["Content-Security-Policy"] = (
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';"
)
return response

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/medcheck/web/app.py | head -100

Repository: Liohtml/MedCheck

Length of output: 4793


🏁 Script executed:

git ls-files | grep -E "(test_|_test\.py|tests\.py)" | head -20

Repository: Liohtml/MedCheck

Length of output: 780


🏁 Script executed:

rg -A 10 "class.*Middleware" src/medcheck/web/app.py

Repository: Liohtml/MedCheck

Length of output: 550


🏁 Script executed:

fd -e py test.*app | grep -i web

Repository: Liohtml/MedCheck

Length of output: 42


🏁 Script executed:

rg -l "_SecurityHeadersMiddleware|security.*header" tests/

Repository: Liohtml/MedCheck

Length of output: 83


🏁 Script executed:

rg "BaseHTTPMiddleware" -A 20 --type py | head -50

Repository: Liohtml/MedCheck

Length of output: 2940


🏁 Script executed:

cat tests/unit/test_web.py

Repository: Liohtml/MedCheck

Length of output: 4289


🏁 Script executed:

web_search
Does Starlette BaseHTTPMiddleware.dispatch() handle exceptions from call_next()?

Repository: Liohtml/MedCheck

Length of output: 277


🌐 Web query:

Starlette BaseHTTPMiddleware exception handling call_next unhandled errors 500 response

💡 Result:

In Starlette, BaseHTTPMiddleware has known limitations regarding exception handling that can lead to unexpected behavior, such as silent failure or inconsistent 500 responses [1][2][3]. The primary issue is that BaseHTTPMiddleware wraps the request-response cycle in a way that may not always correctly propagate or catch exceptions raised by the application, particularly when call_next is involved [1][2]. Under certain conditions, exceptions occurring downstream can be swallowed or handled in a way that prevents standard Starlette exception handlers (like those for HTTPExceptions) from triggering, often resulting in an unhandled 500 response [3]. Key points regarding this behavior include: 1. Exception Swallowing: Exceptions raised inside the application (downstream of the middleware) may not propagate correctly up the stack if BaseHTTPMiddleware consumes or obscures them [1][2]. 2. Inconsistent Handling: Because BaseHTTPMiddleware effectively wraps the application in its own internal logic, it can create a separate error context. This often causes standard middleware components, like ServerErrorMiddleware, to not receive the error as expected, leading to the server returning a default 500 response instead of a custom error page or handled response [4][5][3]. 3. Recommended Mitigation: - Use try/except in dispatch: To handle errors explicitly, wrap your call to call_next(request) in a try/except block within your dispatch method [4][3]. - Return Error Responses: If an exception is caught, you should return an appropriate Response object (e.g., JSONResponse or PlainTextResponse) with the desired status code rather than letting the exception bubble up, which may lead to the issues mentioned above [4][5]. - Use Pure ASGI Middleware: For critical infrastructure or complex error handling where reliability is paramount, consider using standard (pure) ASGI middleware instead of BaseHTTPMiddleware [6]. Pure ASGI middleware interacts directly with the ASGI scope, receive, and send interfaces, avoiding the abstractions and limitations introduced by BaseHTTPMiddleware [1][6]. For more precise control, ensure your error-handling strategy is implemented at the outermost possible layer or use custom exception handlers registered with your application [4][5]. If you must use BaseHTTPMiddleware, explicitly re-raising exceptions in an exception handler can sometimes help force them to be recognized by other layers of the stack [2].

Citations:


🏁 Script executed:

python3 << 'PY'
# Create a minimal test to understand Starlette/FastAPI middleware exception behavior
# This tests whether BaseHTTPMiddleware.dispatch() code after call_next() executes
# when an exception is raised in a route handler

test_code = """
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.testclient import TestClient
from typing import Any

class TestMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next: Any) -> Any:
        print("BEFORE call_next")
        try:
            response = await call_next(request)
            print("AFTER call_next - setting headers")
            response.headers["X-Custom"] = "from-middleware"
            return response
        except Exception as e:
            print(f"Exception caught: {e}")
            raise

app = FastAPI()
app.add_middleware(TestMiddleware)

`@app.get`("/ok")
def ok_route():
    return {"ok": True}

`@app.get`("/error")
def error_route():
    raise ValueError("test error")

# Test normal response
client = TestClient(app, raise_server_exceptions=False)
resp = client.get("/ok")
print(f"OK route status: {resp.status_code}")
print(f"OK route has custom header: {'X-Custom' in resp.headers}")
print(f"OK route custom header value: {resp.headers.get('X-Custom')}")

# Test error response
resp_err = client.get("/error")
print(f"ERROR route status: {resp_err.status_code}")
print(f"ERROR route has custom header: {'X-Custom' in resp_err.headers}")
print(f"ERROR route custom header value: {resp_err.headers.get('X-Custom')}")
"""

print("Test scenario:")
print("- Normal route (/ok) should have X-Custom header")
print("- Error route (/error) that raises exception should also have X-Custom header if middleware code executes after call_next()")
print("\nNote: This test demonstrates the actual behavior of BaseHTTPMiddleware with exceptions.")
PY

Repository: Liohtml/MedCheck

Length of output: 337


🏁 Script executed:

cat tests/unit/test_web.py | tail -50

Repository: Liohtml/MedCheck

Length of output: 1691


Add test for security headers on error responses.

The middleware lacks test coverage for error paths. While standard FastAPI exceptions are converted to 500 responses that should pass through the middleware, BaseHTTPMiddleware has documented edge cases around exception handling. Add the suggested test (test_security_headers_on_unhandled_error) to verify headers are reliably present on error responses. Additionally, wrap call_next() in try/except and return an explicit error response—this is the recommended best practice for BaseHTTPMiddleware to ensure the hardening headers are set even if error handling quirks occur.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/medcheck/web/app.py` around lines 67 - 75, The dispatch middleware method
lacks proper error handling and test coverage. Wrap the call_next() invocation
in a try/except block to catch any exceptions, and return an explicit error
response with the same security headers applied instead of allowing exceptions
to propagate—this is the recommended best practice for BaseHTTPMiddleware.
Additionally, add a test case named test_security_headers_on_unhandled_error
that verifies the security headers (X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, and Content-Security-Policy) are reliably present on error
responses to ensure the middleware properly hardens responses even on error
paths.

Address CodeRabbit review comments:
- Add frame-ancestors 'none' to Content-Security-Policy header
- Pin full CSP value in _EXPECTED_SECURITY_HEADERS test fixture
- Replace loose substring CSP check with frame-ancestors assertion
@rtmalikian

Copy link
Copy Markdown
Contributor Author

Hi, I've addressed both CodeRabbit nitpick comments:

  1. **Added ** to the CSP header — modern CSP-based clickjacking protection matching the existing .

  2. Pinned the full CSP in so both and assert against the complete policy instead of loose substring checks. Updated the dedicated CSP test to verify .

All 12 tests pass. The PR is ready for re-review. 🙏

@Liohtml Liohtml left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for this, Raphael — really thoughtful contribution. The .gitignore output/ fix (#114) is exactly right: those reports carry full PHI and absolutely should never be stageable, and the help-text nudge is a nice touch. The X-Frame-Options / X-Content-Type-Options / Referrer-Policy headers and frame-ancestors 'none' are all solid hardening too.

One blocking issue before this can merge, though — the CSP will break the web UI in a real browser:

script-src 'self' blocks the app's own inline JavaScript. templates/index.html relies heavily on inline scripting that 'self' does not permit:

  • an inline <script> block (~line 668) defining showTab(), fileSelected(), etc.
  • 9 inline event handlers — onclick="showTab(...)", onchange="fileSelected(this)" (lines 421, 424, 427, 440, 449, 477, 541, 545, 619)

Under script-src 'self', a browser will refuse to execute all of these, so tab switching, the dropzone/file picker, and the analyze form stop working. The three new tests don't catch this because TestClient only inspects the header string — it doesn't execute JS or enforce the policy, so they pass even though the page would be broken when actually served.

Two ways forward:

  1. Pragmatic (recommended for this PR): match the template's reality —

    "default-src 'self'; script-src 'self' 'unsafe-inline'; "
    "style-src 'self' 'unsafe-inline'; frame-ancestors 'none';"

    This keeps the UI working today. It's weaker on XSS than a strict policy, but still a real improvement over no CSP, and honest about the current template.

  2. Strict (better, larger): keep script-src 'self' but first refactor the template to remove the inline <script> (move it to /static/app.js) and replace the onclick=/onchange= handlers with addEventListener wiring. That earns the strict CSP legitimately — but it's a bigger change and probably its own PR.

I'd suggest option 1 here so the security headers land without regressing the UI, and we can track the strict-CSP refactor separately. If you go with option 1, could you also add a brief comment noting why 'unsafe-inline' is needed (inline handlers in index.html) so it isn't "tightened" later without the template work?

Everything else looks good to merge once the CSP is sorted. (Note for the maintainer: CI hasn't run yet — first-time-contributor workflows need approval.)


Generated by Claude Code

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Liohtml commented Jun 18, 2026

Copy link
Copy Markdown
Owner

One more thing alongside the CSP note above: the lint job is red, but it's only ruff format --checksrc/medcheck/web/app.py and tests/unit/test_web.py need a run through the formatter. ruff format will sort it. Everything else (ruff check, mypy, the test matrix) is green, so once the formatting and the script-src CSP fix are in, this should be good to go.


Generated by Claude Code

index.html uses inline event handlers (onclick=, onchange=) and an
inline <script> block that 'self' does not permit. Added 'unsafe-inline'
to script-src to keep the UI working. Added a TODO comment to track
moving inline JS to /static/app.js for a stricter CSP in the future.

Also ensured ruff format compliance on both changed files.
@rtmalikian

Copy link
Copy Markdown
Contributor Author

Hi @Liohtml, thanks for the detailed review! I've addressed both points:

1. CSP script-src 'unsafe-inline':

  • Changed script-src 'self'script-src 'self' 'unsafe-inline' to match the template's reality (9 inline event handlers + 1 inline <script> block in index.html)
  • Added a TODO comment tracking the future refactor to move inline JS to /static/app.js for a stricter policy

2. Ruff formatting:

  • Ran ruff format on both src/medcheck/web/app.py and tests/unit/test_web.py — both pass ruff format --check and ruff check

The updated CSP now reads:

default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none';

PR is ready for re-review. Thank you!

@rtmalikian

Copy link
Copy Markdown
Contributor Author

Hi @Liohtml, I've checked the formatting — all 57 files pass ruff format --check cleanly. It looks like the formatting issue was resolved in the latest commit (46861c6) which also added the script-src 'unsafe-inline' CSP fix.

The PR is up to date and ready to merge. Could you re-run the CI to confirm? Thank you!

@rtmalikian

Copy link
Copy Markdown
Contributor Author

Hi @Liohtml, great catch — thank you for the detailed analysis!

The CSP has already been updated to include 'unsafe-inline' in script-src (commit 46861c6). Here's what's in place now:

"default-src 'self'; script-src 'self' 'unsafe-inline'; "
"style-src 'self' 'unsafe-inline'; frame-ancestors 'none';"

I've also added a comment explaining why 'unsafe-inline' is needed and a TODO to refactor inline JS to /static/app.js for a strict CSP in the future.

The PR is ready for re-review. Thank you!

@rtmalikian

Copy link
Copy Markdown
Contributor Author

Hi @Liohtml, I've verified the formatting with ruff 0.15.17 (same version as your CI). Both src/medcheck/web/app.py and tests/unit/test_web.py pass ruff format --check cleanly on the latest commit (46861c6).

It looks like the CI needs fork approval to re-run — could you approve the workflow run? The lint step should pass now.

Thank you for the review!

@Liohtml

Liohtml commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Thanks very much @rtmalikian !

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