Skip to content

Week 11: Fix API error responses in mounted sub-apps + challenge contributor guide - #560

Open
ashike24 wants to merge 11 commits into
GenAI-Security-Project:mainfrom
ashike24:feat/week11-final-polish
Open

Week 11: Fix API error responses in mounted sub-apps + challenge contributor guide#560
ashike24 wants to merge 11 commits into
GenAI-Security-Project:mainfrom
ashike24:feat/week11-final-polish

Conversation

@ashike24

Copy link
Copy Markdown

Week 11: Final bug fix + contributor guide

Per the proposal timeline (Week 11: "Final bug fixes, QA pass, write second blog post, prepare contributor guide"), this PR covers the code and docs deliverables from that list. The second blog post is being handled separately through the usual publishing channel.

1. Fix: is_api_request() didn't detect API requests inside mounted sub-apps

Commit: 491c46e

While doing a final QA pass, I noticed the rate limiter's 429 response was rendering as an HTML page titled "400 - Bad Request" instead of a JSON error reflecting the real status.

Root cause: is_api_request() in finbot/core/error_handlers.py only checked whether request.url.path started with /api/. But /vendor, /ctf, and /admin are mounted as separate ASGI sub-apps, and request.url.path inside a mounted app retains the mount prefix (e.g. /vendor/api/v1/chat, not /api/v1/chat). The check never matched, so every API error response from those three portals - not just 429s, but 403s, 404s, 500s, etc. - was silently falling back to a mislabeled HTML error page instead of a proper JSON response.

Fix: Check for /api/ as a path segment anywhere in the path, rather than only as a prefix. Works for both mounted sub-apps and routes handled directly by the root app.

Verification:

  • Live in browser: fired 11 requests at /vendor/api/v1/chat, confirmed the 11th now returns Content-Type: application/json with a proper structured error body ({"error":{"code":429,"message":"...","type":"api_error"}}), instead of the HTML "400 Bad Request" page.
  • Full test suite: 398 passed, 26 skipped, 6 pre-existing failures (unchanged from baseline, documented since Week 3-4) - 0 regressions.

2. Docs: Challenge contributor guide

Commit: f0b4677

Added docs/contributing-challenges.md, walking through the full process of adding a new CTF challenge: YAML definition structure, the detector class pattern (including the LLM-judge prompt convention), unit test coverage expectations, and a pre-PR checklist.

Uses asi03-ghost-in-the-machine / AgentImpersonationDetector as a worked example throughout, based on the actual code rather than a generic template.

Specifically calls out one non-obvious gotcha: challenge YAML files are auto-discovered on startup, but detector classes are not - they only register if explicitly imported in finbot/ctf/detectors/implementations/init.py. Skipping that step fails silently (the challenge loads, but the detector never resolves at runtime), which seemed worth documenting clearly for future contributors.

Notes for reviewer

ashike24 added 11 commits May 29, 2026 17:23
request.url.path retains the mount prefix (e.g. /vendor/api/v1/chat)
for requests handled by mounted sub-apps like the vendor, ctf, and
admin portals. is_api_request() only checked for a /api/ prefix, so
it never matched these paths - API error responses (429, 403, 404,
500, etc.) from those apps were rendering the generic HTML error page
instead of a JSON response, with the wrong status text shown (e.g.
a 429 rate-limit response displayed as '400 - Bad Request').

Fixed to check for /api/ as a path segment anywhere in the path,
so it works both for mounted sub-apps and routes handled directly
by the root app.

Found and fixed during Week 11 final QA pass. Verified live in
browser (429 now returns correct JSON body/status) and via full
test suite (398 passed, 26 skipped, 6 pre-existing failures
unchanged, 0 regressions).
Walks through adding a new CTF challenge end-to-end: YAML definition,
detector class, the required-but-non-obvious detector registration
step in detectors/implementations/__init__.py, unit test coverage,
and a pre-PR checklist. Uses the asi03-ghost-in-the-machine challenge
and AgentImpersonationDetector as a worked example throughout, based
on the actual patterns in the codebase.

Written for Week 11 per the proposal timeline.
@ashike24

Copy link
Copy Markdown
Author

Note: this diff includes the changes from PRs #521, #532, and #559 as well, since none of those are merged into upstream main yet and this branch was built on top of them (same situation as #559). The changes specific to this PR are:

  • finbot/core/error_handlers.py
  • docs/contributing-challenges.md

Everything else in the diff is prior work already under review in the other open PRs.

@ashike24

Copy link
Copy Markdown
Author

Closing this in favor of a single combined final submission: #567, which includes both changes from this PR along with everything else from the program.

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