Executive brief
Papra's webhook delivery system can be tricked into making HTTP requests to internal server addresses that should be blocked. An authenticated organization member can register a webhook pointing to an attacker-controlled server that issues redirects, causing Papra to reach internal IP ranges (loopback, RFC-1918, cloud metadata services). This could allow reconnaissance of internal network topology or in some cases state-changing requests to internal services.
Technical details
The vulnerability is a server-side request forgery (SSRF) protection bypass in the webhook delivery system. The root cause is in packages/webhooks/src/webhooks.services.ts, where the HTTP client (ofetch) is called without specifying a redirect option, defaulting to 'follow' per the Fetch API specification. SSRF validation occurs at registration and delivery time, checking only the initial registered webhook URL against a blocklist covering 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, and reserved ranges. However, the Fetch API resolves redirects internally without exposing the Location header to application code, so the redirect target is never validated. An authenticated attacker registers a webhook to a public attacker-controlled server, which returns a 302/307 redirect to an internal address; Papra's HTTP client automatically follows the redirect and reaches the blocked internal target. The impact includes internal network reconnaissance (via success/failure patterns), and with HTTP 307, state-changing requests with preserved POST bodies to unauthenticated internal services. No admin role is required; any organization member can register webhooks. The patch is a single-line fix: add redirect: 'manual' to the ofetch.raw() call to disable redirect following.
Affected products
- Papra Papra <= 26.4.0
Timeline
- 2026-06-10: disclosed: Advisory published on GitHub and OSV
- 2026-05-18: patched: Patch released in version 26.5.0