Skip to content

πŸ›‘οΈ Sentinel: [HIGH] Fix information exposure through error messages#154

Open
AGI-Corporation wants to merge 1 commit intomainfrom
sentinel-error-hardening-13873341334655242364
Open

πŸ›‘οΈ Sentinel: [HIGH] Fix information exposure through error messages#154
AGI-Corporation wants to merge 1 commit intomainfrom
sentinel-error-hardening-13873341334655242364

Conversation

@AGI-Corporation
Copy link
Copy Markdown
Owner

@AGI-Corporation AGI-Corporation commented Apr 14, 2026

🚨 Severity: HIGH
πŸ’‘ Vulnerability: Raw exception details (str(e)) were being returned to the client in HTTP 500 responses across multiple endpoints, potentially leaking sensitive system state, file paths, or credentials.
🎯 Impact: An attacker could trigger errors to gain insights into the application's internal architecture, database structure, or environment configuration, facilitating further attacks.
πŸ”§ Fix: Implemented a global @app.exception_handler(Exception) in backend/main.py that logs full tracebacks server-side while returning a generic "Internal server error" to clients. Specifically refactored agents/mistral_agent/agent.py to remove direct leakage of exception strings.
βœ… Verification: Created tests/test_sentinel_errors.py which verifies that sensitive error messages are masked in 500 responses, while ensuring standard FastAPI HTTPException (e.g., 404) and RequestValidationError (422) responses are still correctly passed through to the client.


PR created automatically by Jules for task 13873341334655242364 started by @AGI-Corporation

Summary by CodeRabbit

  • Security
    • Fixed critical information exposure vulnerability where API error responses previously disclosed raw exception messages, database credentials, and sensitive system information to clients.
    • Implemented comprehensive server-side error logging: Full exception tracebacks are now captured and recorded on the server for debugging purposes, while client-facing responses return generic, secure error messages across all endpoints.

- Added global exception handler in backend/main.py to sanitize 500 errors.
- Refactored Mistral agent endpoints to remove detail=str(e).
- Added comprehensive security tests in tests/test_sentinel_errors.py.
- Updated security journal with findings and preventions.

Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

πŸ“ Walkthrough

Walkthrough

The changes implement a security-focused exception handling system across the application. A global FastAPI exception handler is introduced to log full error details server-side while returning generic messages to clients. Individual endpoint handlers are updated accordingly, and tests verify that sensitive exception information is not exposed while maintaining proper HTTP status codes.

Changes

Cohort / File(s) Summary
Sentinel Documentation
.jules/sentinel.md
Added entry documenting information exposure risk from returning raw exception strings in HTTP 500 responses, with guidance to implement global exception handling and avoid detail=str(e) in production.
Backend Exception Handling
backend/main.py, agents/mistral_agent/agent.py
Introduced global exception handler with logging.basicConfig and @app.exception_handler(Exception) to log full tracebacks server-side. Updated three endpoint handlers (/gap-analysis, /code-review, /ask) to log exceptions and return generic HTTP 500 responses instead of exposing exception details to clients.
Error Handling Tests
tests/test_sentinel_errors.py
Added async test suite verifying: sensitive information is not exposed in error responses, HTTP exceptions pass through with proper status codes, and validation errors return correct 422 responses with error details.

Sequence Diagram

sequenceDiagram
    participant Client
    participant FastAPI as FastAPI App
    participant Handler as Global Exception<br/>Handler
    participant Logger
    
    Client->>FastAPI: Request to endpoint
    FastAPI->>FastAPI: Endpoint raises exception
    FastAPI->>Handler: Global handler catches<br/>exception
    Handler->>Logger: Log full traceback<br/>(exc_info=True)
    Logger-->>Handler: Logged
    Handler->>Client: Return generic response<br/>(500 + "Internal server error")
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A rabbit hops with careful care,
To catch exceptions in the air!
No secrets leaked from stack or trace,
Just generic smiles upon your face. 🎭

πŸš₯ Pre-merge checks | βœ… 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (2 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title clearly and specifically describes the main change: fixing information exposure through error messages, which is the core security improvement across all modified files.

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

✨ Finishing Touches
πŸ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sentinel-error-hardening-13873341334655242364

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
tests/test_sentinel_errors.py (1)

8-13: Avoid shared-app route collisions in repeated test runs.

At Line 8, adding a fixed path to the imported global app can accumulate mutable route state if tests are re-run in-process. Prefer a unique temporary path per run.

♻️ Minimal isolation tweak
+import uuid
...
-    `@app.get`("/api/test-error-leakage")
+    path = f"/api/test-error-leakage-{uuid.uuid4()}"
+    `@app.get`(path)
     async def trigger_error():
         raise ValueError("Sensitive database connection string: postgresql://user:password@localhost:5432/db")
...
-        response = await ac.get("/api/test-error-leakage")
+        response = await ac.get(path)
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_sentinel_errors.py` around lines 8 - 13, The test registers a
fixed route on the shared global app which can accumulate routes across
in-process test reruns; change the route registration for trigger_error to use a
unique path per run (e.g., append a uuid or timestamp) so the decorator on
app.get("/api/test-error-leakage") becomes a dynamically-generated path (or
register the handler via app.add_api_route with a unique_path variable) ensuring
no route collisions between runs.
backend/main.py (1)

100-100: Use logger.exception() with request context for cleaner error logs.

At Line 100, the function has access to the request parameter. Using logger.exception() instead of logger.error(..., exc_info=True) is more idiomatic and automatically captures the traceback. Including request method and path adds valuable debugging context.

πŸ› οΈ Suggested adjustment
-    logger.error(f"Unhandled error: {str(exc)}", exc_info=True)
+    logger.exception("Unhandled error on %s %s", request.method, request.url.path)
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/main.py` at line 100, Replace the logger.error(..., exc_info=True)
call with logger.exception to automatically capture the traceback and include
the request context; specifically, call logger.exception with a message that
embeds request.method and request.path (and the exception variable exc) so the
log reads something like "Unhandled error while handling <METHOD> <PATH>: <exc>"
using the existing logger, request and exc symbols.
agents/mistral_agent/agent.py (1)

321-323: Preserve exception causality and use idiomatic logging in exception handlers.

The three exception handlers at lines 321–323, 337–339, and 348–350 re-raise HTTPException without exception chaining (from e), which drops the causal link in tracebacks. Additionally, direct logging.error() calls with f"...{str(e)}" and exc_info=True can be simplified using the logger.exception() method and a module-level logger.

♻️ Proposed refactor
+logger = logging.getLogger(__name__)
+
 MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY", "")
...
-    except Exception as e:
-        logging.error(f"Mistral Gap Analysis Error: {str(e)}", exc_info=True)
-        raise HTTPException(status_code=500, detail="Internal server error")
+    except Exception as e:
+        logger.exception("Mistral Gap Analysis Error")
+        raise HTTPException(status_code=500, detail="Internal server error") from e
...
-    except Exception as e:
-        logging.error(f"Mistral Code Review Error: {str(e)}", exc_info=True)
-        raise HTTPException(status_code=500, detail="Internal server error")
+    except Exception as e:
+        logger.exception("Mistral Code Review Error")
+        raise HTTPException(status_code=500, detail="Internal server error") from e
...
-    except Exception as e:
-        logging.error(f"Mistral Ask Error: {str(e)}", exc_info=True)
-        raise HTTPException(status_code=500, detail="Internal server error")
+    except Exception as e:
+        logger.exception("Mistral Ask Error")
+        raise HTTPException(status_code=500, detail="Internal server error") from e

Also applies to: 337–339, 348–350

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agents/mistral_agent/agent.py` around lines 321 - 323, Replace the ad-hoc
logging.error calls and plain re-raises in the except blocks with a module-level
logger and exception chaining: create or use logger =
logging.getLogger(__name__), call logger.exception(...) instead of
logging.error(f"...{str(e)}", exc_info=True) in the three except blocks shown,
and re-raise the HTTPException using "raise HTTPException(... ) from e" so the
original exception causality is preserved; apply this change to each except
block that currently logs then does "raise HTTPException(...)".
πŸ€– Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@agents/mistral_agent/agent.py`:
- Around line 321-323: Replace the ad-hoc logging.error calls and plain
re-raises in the except blocks with a module-level logger and exception
chaining: create or use logger = logging.getLogger(__name__), call
logger.exception(...) instead of logging.error(f"...{str(e)}", exc_info=True) in
the three except blocks shown, and re-raise the HTTPException using "raise
HTTPException(... ) from e" so the original exception causality is preserved;
apply this change to each except block that currently logs then does "raise
HTTPException(...)".

In `@backend/main.py`:
- Line 100: Replace the logger.error(..., exc_info=True) call with
logger.exception to automatically capture the traceback and include the request
context; specifically, call logger.exception with a message that embeds
request.method and request.path (and the exception variable exc) so the log
reads something like "Unhandled error while handling <METHOD> <PATH>: <exc>"
using the existing logger, request and exc symbols.

In `@tests/test_sentinel_errors.py`:
- Around line 8-13: The test registers a fixed route on the shared global app
which can accumulate routes across in-process test reruns; change the route
registration for trigger_error to use a unique path per run (e.g., append a uuid
or timestamp) so the decorator on app.get("/api/test-error-leakage") becomes a
dynamically-generated path (or register the handler via app.add_api_route with a
unique_path variable) ensuring no route collisions between runs.

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dc4b4692-fe01-43a0-8c1d-a66e805a1edc

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between c9be2df and 67c771a.

πŸ“’ Files selected for processing (4)
  • .jules/sentinel.md
  • agents/mistral_agent/agent.py
  • backend/main.py
  • tests/test_sentinel_errors.py

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.

1 participant