CVE-2026-108770 Overview
CVE-2026-108770 is a server-side request forgery (SSRF) vulnerability in Appwrite versions up to 2.3.0. The flaw resides in the PublicHostname function within src/Appwrite/Platform/Modules/Avatars/Http/Screenshots/Get.php, part of the Browser Screenshot Service. An attacker can manipulate the url argument to force the Appwrite server to issue HTTP requests to arbitrary destinations. The attack is remotely exploitable and requires no authentication or user interaction. Appwrite resolved the issue in version 2.4.0 with commit 393255e7302ae5503331d45802e2eee01c6a47fe. The weakness is classified under CWE-918: Server-Side Request Forgery.
Critical Impact
Unauthenticated remote attackers can abuse the screenshot endpoint to probe internal networks, access cloud metadata services, or interact with services not exposed to the public internet.
Affected Products
- Appwrite versions up to and including 2.3.0
- Browser Screenshot Service component (src/Appwrite/Platform/Modules/Avatars/Http/Screenshots/Get.php)
- Avatars module endpoints that accept a user-controlled remote url
Discovery Timeline
- 2026-10-11 - CVE-2026-108770 published to NVD
- 2026-10-13 - Last updated in NVD database
Technical Details for CVE-2026-108770
Vulnerability Analysis
The Browser Screenshot Service accepts a user-supplied url parameter and fetches that URL server-side to render a screenshot. In vulnerable builds, the PublicHostname validator did not sufficiently constrain the destination to publicly routable hosts. An attacker can submit a URL pointing at internal infrastructure, loopback addresses, or cloud instance metadata endpoints such as 169.254.169.254. The Appwrite backend then performs the outbound request on the attacker's behalf and may return response contents or side-channel signals in the screenshot output. EPSS currently rates this vulnerability at 0.406% with a percentile of 33.291 as of 2026-10-16.
Root Cause
The root cause is incomplete validation of user-supplied URLs before dispatching outbound HTTP requests. The original PublicHostname validator checked hostname structure but did not confirm that DNS resolution produced only publicly routable addresses. This allowed DNS rebinding, private-IP literals, and metadata-service hostnames to pass validation.
Attack Vector
The attack vector is network-based and unauthenticated. An adversary issues a crafted request to the vulnerable avatars screenshot endpoint with a url parameter targeting an internal resource. Common SSRF targets include cloud metadata services, internal admin consoles, Redis or Elasticsearch instances bound to localhost, and container orchestration APIs.
// Patch excerpt: new PublicURL validator added in commit 393255e
<?php
namespace Appwrite\Network\Validator;
use Utopia\Domains\Domain;
use Utopia\Validator\URL;
/**
* Validates an http(s) URL whose host is a known public domain (or a public
* IP literal) that resolves only to publicly routable addresses. Used on
* endpoints that fetch user-controlled URLs.
*/
class PublicURL extends URL
{
private string $reason = '';
public function __construct()
{
parent::__construct(['http', 'https']);
}
public function getDescription(): string
{
return $this->reason !== '' ? $this->reason : parent::getDescription();
}
public function isValid($value): bool
{
$this->reason = '';
// ...resolution and public-address checks follow
}
}
Source: Appwrite Commit 393255e
Detection Methods for CVE-2026-108770
Indicators of Compromise
- Requests to /v1/avatars/screenshot or related avatars endpoints containing url parameters pointing at RFC1918 ranges, 127.0.0.0/8, 169.254.0.0/16, or ::1
- Outbound HTTP requests originating from the Appwrite container toward internal service ports (6379, 9200, 8500, 2379, 5984)
- DNS queries from the Appwrite host that resolve to private or link-local addresses shortly after public lookups (indicative of DNS rebinding)
- Screenshot responses whose rendered content matches internal admin UIs or cloud metadata JSON documents
Detection Strategies
- Inspect Appwrite access logs for avatars screenshot requests with suspicious url values and correlate with downstream network flows
- Deploy egress monitoring on the Appwrite worker containers to flag any outbound connections to non-public destinations
- Compare the installed Appwrite version against 2.4.0 using software inventory tooling and flag any build at or below 2.3.0
Monitoring Recommendations
- Enable WAF or reverse-proxy logging in front of Appwrite and alert on url query parameters containing IP literals or non-standard hostnames
- Monitor cloud instance metadata service (IMDS) access logs where available, and enforce IMDSv2 to raise the exploitation bar
- Add Appwrite host network telemetry to the security data lake and build detections for anomalous internal destinations initiated by the screenshot worker
How to Mitigate CVE-2026-108770
Immediate Actions Required
- Upgrade Appwrite to version 2.4.0 or later, which includes the PublicURL validator introduced in commit 393255e
- Restrict egress from Appwrite containers so they cannot reach internal subnets, loopback, or metadata endpoints
- Enforce IMDSv2 on AWS and equivalent protections on other cloud providers to block token-less metadata retrieval
- Review historical access logs for the avatars screenshot endpoint to identify any prior exploitation attempts
Patch Information
The fix is delivered in Appwrite Release 2.4.0 via Pull Request #13995 and commit 393255e7302ae5503331d45802e2eee01c6a47fe. The patch introduces a new PublicURL validator in src/Appwrite/Network/Validator/PublicURL.php and wires it into the Favicon and Screenshots avatar endpoints so that only URLs resolving to publicly routable addresses are fetched. See the VulDB advisory for additional context.
Workarounds
- Disable or firewall the avatars screenshot and favicon endpoints at the reverse proxy until the upgrade is applied
- Place Appwrite workers behind an egress proxy that only permits connections to allowlisted public destinations
- Apply network policies (Kubernetes NetworkPolicy, security groups) that deny traffic from Appwrite pods to RFC1918 ranges and link-local addresses
# Example: block private and link-local egress from the Appwrite worker container
iptables -A OUTPUT -o eth0 -d 10.0.0.0/8 -j REJECT
iptables -A OUTPUT -o eth0 -d 172.16.0.0/12 -j REJECT
iptables -A OUTPUT -o eth0 -d 192.168.0.0/16 -j REJECT
iptables -A OUTPUT -o eth0 -d 169.254.0.0/16 -j REJECT
iptables -A OUTPUT -o eth0 -d 127.0.0.0/8 -j REJECT
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

