CVE-2026-77066: Omnivore Server-Side Request Forgery via the scanFeeds GraphQL Query
The scanFeedsResolver in packages/api/src/resolvers/subscriptions/index.ts passes the caller-supplied url straight to axios.get(url, rssParserConfig()) with no address validation. The same file guards the subscribe path with validateUrl(), which rejects private and reserved ranges through the private-ip library, and createPageSaveRequest applies the same check, so the omission is specific to this resolver. An authenticated user can direct the server to request arbitrary internal endpoints. The response is parsed as a feed or as HTML and the resolver returns the resulting url, title, description and type fields, so disclosure is limited to feed-shaped metadata and to link elements advertising RSS or Atom feeds; requests that do not parse still distinguish reachable ports from unreachable ones through the resulting error.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
In scanFeedsResolver, apply the same validateUrl() / private-ip reserved/private range rejection that is used for the subscribe path (and createPageSaveRequest) to the url argument before passing it to axios.get(url, rssParserConfig()).
scanFeedsResolver (packages/api/src/resolvers/subscriptions/index.ts) URL validation before request (axios.get) = Enable address validation (use validateUrl/private-ip range checks) for the caller-supplied url before calling axios.get - Compensating control
Restrict outbound network access from the application/server so it cannot reach arbitrary internal endpoints (e.g., block RFC1918/private, link-local, and other internal networks or allow only required egress destinations).
Event History
Frequently Asked Questions
Who can exploit this issue?
An attacker needs an authenticated Omnivore account or other valid credentials that allow access to the scanFeeds GraphQL query. No user interaction is required, and the attacker can supply the target URL.
Which requests are vulnerable?
The exposure is specific to the scanFeeds resolver. Other paths in the same file, including subscription handling and page-save requests, use validateUrl() to reject private and reserved addresses.
What can an attacker learn through the vulnerable request?
Responses are parsed as feeds or HTML, with returned data limited to URL, title, description, and type fields or discovered RSS/Atom feed links. Even when parsing fails, error behavior can distinguish reachable internal ports from unreachable ones.
How can defenders identify possible exploitation?
Review use of the scanFeeds GraphQL query for caller-supplied URLs targeting private or reserved IP ranges, internal hostnames, or unusual ports. Requests that produce parser errors may still indicate internal service or port probing.
What mitigation is indicated if the resolver cannot be patched immediately?
Apply equivalent address validation before scanFeeds performs its outbound request, rejecting private and reserved ranges as validateUrl() does in the protected paths. Restricting the server's outbound network access can also limit access to internal endpoints.