AEV-2026-0037
Rowboat authorizes the project action, then checks only the URL scheme, on custom MCP server and webhook destinations (CVE-2026-86122)
Rowboat's AddCustomMcpServerUseCase calls its project action authorization policy correctly, then a locally defined validateHttpHttpsUrl that checks only that the value is a well formed http or https URL. The stored URL is later read by the agent runtime and connected to or fetched with no destination check. A proposed fix predates the report by five weeks and remains open and unmerged.
Affected
- Organisation
- Rowboat Labs
- Product
- Rowboat
- Component
- AddCustomMcpServerUseCase's validateHttpHttpsUrl, and agent-tools.ts's invokeMcpTool and invokeWebhookTool
- Versions
- Through version 0.9.1, confirmed at the v0.9.1 tag; unknown for v0.9.2 and v0.9.3
- Configurations
- A registered project member permitted to configure a custom MCP server or a project webhook
Execution authority facts
Fields the evidence does not establish are shown as unknown rather than guessed.
- Intended task
- A project member configures a custom MCP server or a project webhook for their project's agent runtime
- Agent
- Rowboat's own server process, through AddCustomMcpServerUseCase at configuration time and invokeMcpTool's getMcpClient call or invokeWebhookTool's fetch call at runtime
- Delegating actor
- The project member who added the custom MCP server URL or configured the project's webhook URL
- Action
- Opened an MCP session or sent a signed webhook POST request to a project member named destination, with no check on whether that destination was private, loopback, link local or a cloud metadata address
- Target resource
- Whatever private, loopback, link local or cloud metadata destination the project member names as the custom MCP server URL or the webhook URL
- Environment
- Wherever the Rowboat server process is deployed, reaching whatever network that deployment sits inside
- Credentials used
- None of Rowboat's own reaches the destination beyond the request itself; the webhook path attaches a JWT signed with the project's own secret, addressed to whatever destination the caller named, not a credential that constrains the destination
- Privileges available
- The Rowboat server process's own network reachability from its deployment location
- Authority presented
- A project member's authorization, confirmed by projectActionAuthorizationPolicy.authorize, to perform the configure custom MCP server or webhook project action
- Authority required
- Authorization for the specific destination the configured URL directs the server's outbound connection or request to
- Applicable policy
- projectActionAuthorizationPolicy.authorize, confirmed called before the URL is validated or persisted; validateHttpHttpsUrl, confirmed to check only that the URL's protocol is http or https
- Approval mechanism
- none, beyond the project action authorization already described
- Required approver
- unknown
- Independent approval
- no
- Action binding
- The action's authority bound to the project action of configuring a named MCP server or webhook; the destination itself was never independently checked before the server later connected to or fetched it
- Sequence context
- Configuration, authorize, then a usage quota check, then a scheme only check, then persist, and later use, an agent runtime reading the stored URL and connecting or fetching it, are separate steps in the code this record read; no destination check appears at either step
Impact
- Consequence
- The Rowboat server process's own outbound MCP connection or webhook POST request directed at a project member named destination, with the webhook path returning the full response body and, on failure, the response status and status text, to the calling agent
- Reach
- Whatever internal network the Rowboat deployment sits inside, reachable from the server's own network position
- Reversibility
- unknown
- Detectability
- unknown
- Propagation
- Potential: the webhook path's returned status, status text and full response body function as a probe for internal service and endpoint enumeration; not established as observed against a real deployment
- Recovery
- No patched version confirmed by this record. Pull request 547 proposes destination validation for both paths; it predates this report by five weeks, is not linked to it, and remains open and unmerged.
Evidence
Primary sources
- Server-side request forgery via user-configured custom MCP server URLs and webhook URLs (no private-IP/metadata guard) reachable by any project member (rowboatlabs/rowboat (GitHub Issues))
- add-custom-mcp-server.use-case.ts at v0.9.1 (AddCustomMcpServerUseCase, validateHttpHttpsUrl) (rowboatlabs/rowboat (GitHub, source))
- agent-tools.ts at v0.9.1 (invokeWebhookTool and invokeMcpTool) (rowboatlabs/rowboat (GitHub, source))
Supporting sources
- fix(security): add SSRF protection for webhook and MCP server URLs (rowboatlabs/rowboat (GitHub Pull Requests))
- Releases: rowboatlabs/rowboat (Rowboat Labs, rowboatlabs/rowboat (GitHub))
- Security: rowboatlabs/rowboat (no maintainer-published advisories) (rowboatlabs/rowboat (GitHub Security Advisories))
- CVE-2026-86122 (CVE Program (cve.org))
- GHSA-jmxm-qmrf-xrpp: Rowboat through 0.9.1 fails to validate custom MCP server and webhook URLs (GitHub Advisory Database)
- Reproduction status
- Independently confirmed by Moona Intelligence reading the affected source directly at the v0.9.1 tag rather than by running an exploit against a live deployment. Rowboatlabs/rowboat's own security advisories page still lists none published by the maintainers, but GHSA-jmxm-qmrf-xrpp, a general GitHub Advisory Database mirror of this CVE, was read directly on 7 September 2026 and corroborates the mechanism; every CNA and CVE aggregator this session attempted to fetch directly remained blocked by this session's network egress policy on both 6 and 7 September 2026.
- Evidence state
- Confirmed
Known unknowns
- Whether this has been exploited against a real Rowboat deployment.
- Whether Rowboat's v0.9.2, v0.9.3 or v0.9.4 pre releases changed the specific functions this entry read at v0.9.1; direct fetches of the equivalent files at those tags all returned not found responses.
- Whether getMcpClient's own internal transport construction contains any destination check beyond what the call site passes into it; this session's attempts to read that file directly returned not found responses.
- Whether pull request 547's own changed code matches its description in every particular, since this session read it through a page summarization tool rather than the raw diff.
- Which body served as the assigning CVE Numbering Authority for CVE-2026-86122; the GHSA mirror read directly on 7 September 2026 does not itself state one. A separately reported CVSS 3.1 score of 5.0 also remains unconfirmed by any primary record, though the CVSS 4.0 vector and score are now confirmed directly from that mirror.
Limitations
- This session's direct fetch of cve.org, nvd.nist.gov, vulncheck.com and several other CVE aggregators remained blocked by this session's network egress policy on repeated attempts across 6 and 7 September 2026; the CVE's publication date, affected range and CWE are corroborated by a direct read of GHSA-jmxm-qmrf-xrpp, a general GitHub Advisory Database mirror marked Unreviewed and NVD sourced, rather than by a primary CNA record.
- The GitHub issue and the pull request were retrieved through this session's automated page fetch and summarization tool rather than read as raw markup; the two source files this entry quotes directly, the use case and agent-tools.ts, were confirmed as complete verbatim content by that same tool.
Claim provenance
- independent-reporting
The primary issue, filed by a reporter independent of Rowboat's maintainers, opened 13 June 2026 and still open, names the two affected file paths, the validateHttpHttpsUrl function, the getMcpClient and webhook tool runtime sinks, and gives example private and metadata destinations.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach. - verified
This session read the affected source directly at the v0.9.1 tag, confirming AddCustomMcpServerUseCase.execute calls projectActionAuthorizationPolicy.authorize, then usageQuotaPolicy.assertAndConsumeProjectAction, then a locally defined validateHttpHttpsUrl that throws only if the URL's protocol is neither http: nor https:, then persists the result unchanged.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach. - verified
This session read invokeWebhookTool and invokeMcpTool directly at the v0.9.1 tag, confirming both read a stored, never validated URL, checking only that it is present, and confirming invokeWebhookTool's fetch call, its error message built from response.status and response.statusText, and its return of the complete parsed JSON response body on success.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach. - verified
The open pull request, read through this session's page fetch tool, proposes destination validation rejecting private, loopback and link local ranges and cloud metadata addresses for both affected URL fields. It was opened 10 May 2026, five weeks before the primary issue, and this session found no reference connecting the two in either direction. It is not merged.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach. - verified
This session confirmed directly that rowboatlabs/rowboat's own maintainers have not published a GitHub Security Advisory of their own for this mechanism, unlike the Grafana and OGX MCP SSRF entries. This is narrower than treating no GHSA as existing at all: the general GitHub Advisory Database separately mirrors this CVE, read directly and provenanced below.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach. - verified
This session read GHSA-jmxm-qmrf-xrpp directly on 7 September 2026, confirming it formally assigns CVE-2026-86122, a CWE-918 classification, a CVSS 4.0 vector scoring 5.3, and a 5 September 2026 publish date, and that its own references name issue 621 and both affected source files this entry already cites. The advisory is marked Unreviewed by GitHub, meaning NVD sourced rather than independently curated, and does not itself state an assigning CVE Numbering Authority.
The User Was Authorized to Configure the MCP Server. They Were Not Authorized to Turn Rowboat Into a Route to Every Address It Could Reach.
