Skip to content

🛡️ Sentinel: [CRITICAL] Fix hardcoded staff password#42

Open
LVT-ENG wants to merge 2 commits intomainfrom
jules-8424711469455478886-e92ce9eb
Open

🛡️ Sentinel: [CRITICAL] Fix hardcoded staff password#42
LVT-ENG wants to merge 2 commits intomainfrom
jules-8424711469455478886-e92ce9eb

Conversation

@LVT-ENG
Copy link
Copy Markdown
Member

@LVT-ENG LVT-ENG commented Mar 29, 2026

This PR addresses a critical security vulnerability where the staff access password was hardcoded in the frontend JavaScript, making it visible to anyone who inspects the source code.

Changes:

  1. Backend Security Enhancement: Added a new POST endpoint /api/verify-staff that validates the password against an environment variable (STAFF_PASSWORD).
  2. Timing Attack Protection: Used hmac.compare_digest for password verification to mitigate timing-based side-channel attacks.
  3. Frontend Refactor: Updated js/main.js to remove the hardcoded check and instead perform an asynchronous fetch call to the new backend endpoint.
  4. Testing: Introduced backend/tests/test_staff.py to ensure the new endpoint correctly handles successful logins, incorrect passwords, and edge cases.
  5. Environment Configuration: Added STAFF_PASSWORD to the supported environment variables, defaulting to the previous value for development compatibility.

This change ensures that sensitive credentials remain on the server and are properly protected.


PR created automatically by Jules for task 8424711469455478886 started by @LVT-ENG

- Removed hardcoded 'SAC_MUSEUM_2026' password from client-side `js/main.js`.
- Implemented secure backend verification endpoint `/api/verify-staff` in `backend/main.py`.
- Added `StaffLogin` model to `backend/models.py`.
- Password comparison now uses `hmac.compare_digest` to prevent timing attacks.
- Staff password is now configurable via the `STAFF_PASSWORD` environment variable.
- Added comprehensive integration tests in `backend/tests/test_staff.py`.
- Verified UI flow with automated Playwright verification.

Co-authored-by: LVT-ENG <214667862+LVT-ENG@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 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.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
_deploy_build Ready Ready Preview, Comment Mar 29, 2026 4:56am
tryonyou-org Ready Ready Preview, Comment Mar 29, 2026 4:56am

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request migrates staff password verification from the frontend to a new backend API endpoint /api/verify-staff. The implementation includes a StaffLogin model, secure password comparison using hmac.compare_digest, and a Vite proxy configuration. Feedback identifies a critical security risk regarding the hardcoded default password in the backend and suggests using monkeypatch in tests to avoid hardcoding credentials.

Copy link
Copy Markdown
Member Author

@LVT-ENG LVT-ENG left a comment

Choose a reason for hiding this comment

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

Yes

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@LVT-ENG
Copy link
Copy Markdown
Member Author

LVT-ENG commented Mar 31, 2026

Yes

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 moves the staff “private pass” verification from a hardcoded frontend string to a backend-validated endpoint, so the password is no longer exposed in client-side JavaScript.

Changes:

  • Added a new FastAPI endpoint (POST /api/verify-staff) to validate staff credentials server-side.
  • Refactored the frontend staff check to call the backend endpoint via fetch.
  • Added a Vite dev proxy for /api to forward requests to the backend during local development, plus new backend tests for the staff verification endpoint.

Reviewed changes

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

Show a summary per file
File Description
vite.config.js Adds dev-time /api proxy to the FastAPI server.
js/main.js Replaces hardcoded staff password check with an async call to /api/verify-staff.
backend/main.py Introduces /api/verify-staff and reads STAFF_PASSWORD from env.
backend/models.py Adds StaffLogin request model for the staff verification endpoint.
backend/tests/test_staff.py Adds tests intended to cover staff verification success/failure cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


@app.post("/api/verify-staff")
def verify_staff(login: StaffLogin):
"""🛡️ Secure staff password verification via backend."""
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

STAFF_PASSWORD is read from the environment with no default and can be None/empty. hmac.compare_digest(login.password, STAFF_PASSWORD) will raise a TypeError when STAFF_PASSWORD is None, causing a 500 instead of a clean auth failure. Please explicitly handle the missing/empty configuration (e.g., fail closed with a clear 5xx error, or provide an explicit dev-only default as described in the PR).

Suggested change
"""🛡️ Secure staff password verification via backend."""
"""🛡️ Secure staff password verification via backend."""
# Ensure staff authentication is properly configured before comparing.
if not STAFF_PASSWORD:
# Fail closed with a clear server-side configuration error.
raise HTTPException(
status_code=500,
detail="STAFF_PASSWORD is not configured on the server.",
)

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,23 @@
import pytest
from fastapi.testclient import TestClient
from main import app
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

The tests import app from main, but the backend app appears to live at backend.main (see backend/tests/test_main.py). As written this will fail with ModuleNotFoundError in most test runs; align the import with the existing test pattern.

Suggested change
from main import app
from backend.main import app

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,23 @@
import pytest
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

pytest is imported but not used in this test module. Removing unused imports keeps the test suite clean (and avoids lint failures if linting is enabled for Python).

Suggested change
import pytest

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +20

client = TestClient(app)

def test_verify_staff_success():
"""Test successful staff verification with correct password."""
response = client.post("/api/verify-staff", json={"password": "SAC_MUSEUM_2026"})
assert response.status_code == 200
assert response.json() == {"status": "SUCCESS", "message": "Acceso concedido al búnker."}

def test_verify_staff_failure():
"""Test failed staff verification with incorrect password."""
response = client.post("/api/verify-staff", json={"password": "WRONG_PASSWORD"})
assert response.status_code == 401
assert response.json() == {"detail": "Credencial de acceso denegada."}

def test_verify_staff_empty():
"""Test staff verification with empty password."""
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

These tests hardcode a specific password but don't configure STAFF_PASSWORD for the app under test. Since STAFF_PASSWORD is loaded from the environment at import time (and may be None), the success case is likely to fail depending on the test environment. Prefer setting a test password via monkeypatch (e.g., patch backend.main.STAFF_PASSWORD or set the env var before importing the app) and use that same value in the request.

Suggested change
client = TestClient(app)
def test_verify_staff_success():
"""Test successful staff verification with correct password."""
response = client.post("/api/verify-staff", json={"password": "SAC_MUSEUM_2026"})
assert response.status_code == 200
assert response.json() == {"status": "SUCCESS", "message": "Acceso concedido al búnker."}
def test_verify_staff_failure():
"""Test failed staff verification with incorrect password."""
response = client.post("/api/verify-staff", json={"password": "WRONG_PASSWORD"})
assert response.status_code == 401
assert response.json() == {"detail": "Credencial de acceso denegada."}
def test_verify_staff_empty():
"""Test staff verification with empty password."""
import main
TEST_STAFF_PASSWORD = "SAC_MUSEUM_2026"
client = TestClient(app)
def test_verify_staff_success(monkeypatch):
"""Test successful staff verification with correct password."""
monkeypatch.setattr(main, "STAFF_PASSWORD", TEST_STAFF_PASSWORD, raising=False)
response = client.post("/api/verify-staff", json={"password": TEST_STAFF_PASSWORD})
assert response.status_code == 200
assert response.json() == {"status": "SUCCESS", "message": "Acceso concedido al búnker."}
def test_verify_staff_failure(monkeypatch):
"""Test failed staff verification with incorrect password."""
monkeypatch.setattr(main, "STAFF_PASSWORD", TEST_STAFF_PASSWORD, raising=False)
response = client.post("/api/verify-staff", json={"password": "WRONG_PASSWORD"})
assert response.status_code == 401
assert response.json() == {"detail": "Credencial de acceso denegada."}
def test_verify_staff_empty(monkeypatch):
"""Test staff verification with empty password."""
monkeypatch.setattr(main, "STAFF_PASSWORD", TEST_STAFF_PASSWORD, raising=False)

Copilot uses AI. Check for mistakes.
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