Skip to content

fix(mcp): reject negative limit in FinStripe list_transfers - #565

Open
Deez-Automations wants to merge 2 commits into
GenAI-Security-Project:mainfrom
Deez-Automations:fix/finstripe-negative-limit-330
Open

fix(mcp): reject negative limit in FinStripe list_transfers#565
Deez-Automations wants to merge 2 commits into
GenAI-Security-Project:mainfrom
Deez-Automations:fix/finstripe-negative-limit-330

Conversation

@Deez-Automations

Copy link
Copy Markdown

Summary

Fixes #330.

list_transfers's limit parameter flowed straight through to the repository's SQLAlchemy .limit() call with no validation. Confirmed the actual behavior: on SQLite, a negative limit is silently treated as "no limit at all," returning the full result set — undefined/surprising behavior rather than a clear error.

Fix

Rejects negative limits with a clear error. Zero (a legitimate "give me nothing" request) and ordinary positive limits are unaffected.

Test plan

  • New test file tests/unit/mcp/test_finstripe.py — reproduces the exact issue repro steps against the unfixed code first (confirmed the negative limit was silently returning all transfers instead of erroring), then confirms the fix
  • Covers the zero-limit edge case explicitly (legitimate value, must not be rejected)
  • Regression test confirms ordinary positive limits are unaffected
  • pytest tests/unit/mcp/test_finstripe.py — 3/3 passing

…curity-Project#330)

limit flowed straight through to the repository's SQLAlchemy .limit()
call with no validation. A negative value produces undefined database
behavior instead of a clear error -- confirmed it's silently treated as
"no limit" on SQLite, returning the full result set rather than failing
or being ignored as one might expect.

Rejects negative limits with a clear error. Zero (a legitimate "give me
nothing" request) and ordinary positive limits are unaffected.

Fixes GenAI-Security-Project#330
Copilot AI lite review requested due to automatic review settings August 11, 2026 15:34

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 addresses issue #330 by adding input validation to the FinStripe MCP server’s list_transfers tool so negative limit values are rejected instead of being passed through to SQLAlchemy’s .limit() (which can behave unexpectedly, e.g., SQLite treating negative limits as “no limit”).

Changes:

  • Add a guard in list_transfers to reject limit < 0 with a clear error payload.
  • Add new unit tests covering negative limit rejection, zero-limit behavior, and a positive-limit regression case.
  • Add tests/unit/mcp/__init__.py to ensure the new test module is import/package-safe.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
finbot/mcp/servers/finstripe/server.py Adds negative-limit validation in list_transfers before calling the repository.
tests/unit/mcp/test_finstripe.py Adds regression/edge-case tests for list_transfers limit handling.
tests/unit/mcp/init.py Ensures tests.unit.mcp is treated as a package for test discovery/import behavior.
Suppressed comments (1)

tests/unit/mcp/test_finstripe.py:11

  • This part of the docstring states that list_transfers "has no validation on limit", but the PR adds validation. Reword to clarify it was verified against the pre-fix source so the docstring stays correct.
Verified against source before writing anything: finbot/mcp/servers/
finstripe/server.py's list_transfers (create_finstripe_server) has no
validation on `limit`; it flows straight into PaymentTransactionRepository
.list_for_vendor's SQLAlchemy .limit(limit) call.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/unit/mcp/test_finstripe.py Outdated
Comment on lines +3 to +6
GitHub issue #330 (Bug_121_MUST_FIX, MCP-LIST-006): list_transfers passes
`limit` straight through to the repository's query with no bounds check
at all -- a negative limit produces undefined database behavior instead
of a clear, diagnosable error.
Comment on lines +139 to 144
if limit < 0:
return {"error": "limit must be zero or a positive integer"}

with db_session() as db:
repo = PaymentTransactionRepository(db, session_context)
transactions = repo.list_for_vendor(vendor_id, limit=limit)
…pilot review, GenAI-Security-Project#330)

The original fix only guarded the MCP tool's list_transfers wrapper.
PaymentTransactionRepository.list_for_vendor is a shared repository with
other real callers -- finbot/apps/vendor/routes/api.py's
GET /payments/transactions route takes limit/offset directly as
user-controlled query parameters with zero validation of its own, and
was still reachable with a negative limit even after the MCP-only fix.
Caught by Copilot's review on PR GenAI-Security-Project#565.

Moved the authoritative guard into list_for_vendor itself, covering both
limit AND offset (offset had the identical undefined-behavior gap, not
mentioned in the original issue but caught while fixing the same root
cause). The vendor route now catches the resulting ValueError and
returns a proper 400, matching this file's own existing error-handling
convention used elsewhere (e.g. invoice creation). The two other
list_for_vendor callers in that file use a hardcoded limit=1000 with no
user input, so they're unaffected.
@Deez-Automations

Copy link
Copy Markdown
Author

Addressed the Copilot review feedback:

  • Docstring tense: fixed, now describes the pre-fix behavior in past tense.
  • Validation only in the MCP layer (the important one): confirmed — I traced every real caller of list_for_vendor and found finbot/apps/vendor/routes/api.py's GET /payments/transactions route takes limit/offset directly as user-controlled query parameters with zero validation, and was still reachable with a negative limit even after the MCP-only fix. Moved the authoritative guard into PaymentTransactionRepository.list_for_vendor itself so every caller is protected, not just the MCP tool. Also caught that offset has the identical gap (not in the original issue, but the same root cause) and guarded that too. The vendor route now catches the resulting ValueError and returns a proper 400, matching this file's own existing error-handling convention. The other two list_for_vendor call sites in that file use a hardcoded limit=1000 with no user input, so they're unaffected.

9/9 tests passing after both changes (6 in the original file, 3 new ones directly exercising the repository-level guard).

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.

Bug_121_MUST_FIX: Test Case MCP-LIST-006: Negative limit value accepted without validation — undefined database behaviour

2 participants