June 5, 2026
Secure Implementation Of Link Previews In Chat Applications
Don’t let link previews pwn your infrastructure — a complete security guide.
23
8 min read
Abstract
Link previews in chat applications — where the system automatically fetches a title, description, and image from a user‑supplied URL — introduce significant security risks. Attackers can exploit this functionality to perform Server‑Side Request Forgery (SSRF), Denial of Service (DoS), Cross‑Site Scripting (XSS), privacy leakage, and data exfiltration. This report analyzes these threat vectors and presents a defense‑in‑depth mitigation strategy. The recommended approach combines strict application‑level controls (URL scheme whitelisting, private IP blocklisting, timeouts, size limits, safe HTML parsing, output sanitization, IP Pinning, and aggressive caching) with network segmentation — specifically placing the preview fetcher inside a Demilitarized Zone (DMZ). The DMZ isolates the fetcher from internal networks, preventing lateral movement in case of compromise. Firewall rules allow only outbound HTTP/HTTPS requests from the DMZ to the internet and deny any direct inbound internet access or internal network connections. Additional mitigations include using a forward proxy with IP blocklists, sandboxed containers, rate limiting, and client‑side safe rendering (plain text, not HTML). This layered architecture ensures that even if the fetcher contains unknown vulnerabilities, the overall system remains resilient. The report concludes that automatic link previews can be implemented securely only when both application‑level hardening and network‑level isolation (DMZ) are enforced together.
Introduction
Modern chat applications (Telegram, Slack, WhatsApp, Microsoft Teams) enhance user experience by showing a rich preview when a user sends a link. However, the automatic fetching of arbitrary URLs expands the attack surface significantly. An attacker can craft a malicious link that, when previewed, compromises the chat server, leaks internal data, or attacks the client.
Threat Landscape: Link Preview Vulnerabilities
1. Server‑Side Request Forgery (SSRF):
1.1) Description: The preview server is tricked into making requests to internal IP addresses, localhost, cloud metadata endpoints, or internal APIs. The attacker controls the target URL.
1.2) Real word example:
CVE‑2022‑25876 (link-preview-js npm package) — SSRF due to flawed DNS rebinding protection, enabling local network scanning.
1.3) Impacts:
a) Reading cloud metadata (e.g., AWS 169.254.169.254) → credential theft.
b) Port scanning internal services.
c) Accessing internal admin panels or APIs.
d) Using file:// protocol (if allowed) to read local files and …
2. Denial of Service (DOS):
2.1) Description: Resource exhaustion caused by slow responses, huge payloads, decompression bombs, or redirect loops.
2.2) Real word example:
CVE-2023–5969(Denial of Service via Link Preview in /api/v4/redirect_location) allowing attackers to send specially crafted requests that exploit caching of large objects, leading to excessive memory consumption.
2.3) Impacts:
a) Chat service becomes unresponsive.
b) Increased cloud costs due to autoscaling triggered by many stuck requests.
3. Cross Site Scripting(XSS):
3.1) Description: The metadata (title, description) fetched from the link is rendered unsafely in the chat client, allowing script injection.
3.2) Real word example:
CVE‑2025‑11987 (WordPress Visual Link Preview) — Stored XSS due to insufficient sanitization of link preview data.
3.3) Impact:
Session hijacking, defacement, credential theft, or malware distribution.
4. Privacy Leakage And Data Exfiltration:
4.1) Description: The act of fetching a preview leaks information (IP address, User‑Agent, time) to the link owner. Additionally, sensitive data can be exfiltrated via the preview process.
4.2) Real word example:
CVE‑2018‑20436 (Telegram Secret Chat) — GET requests sent before the message is actually sent, creating a side‑channel to detect when a user views a link.
4.3) Impact:
Leak of user online status, geolocation (approximate), or private conversation snippets.
5. Protocol Smuggling & Phishing:
5.1 ) Protocol abuse — javascript://, data://, file://, gopher:// can bypass validation or lead to client‑side execution.
5.2 ) Content spoofing — Preview shows a legitimate domain (e.g., google.com) while the actual destination is evil.com. Users trust the preview and click.
6. XXE (XML External Entity):
If the link preview service processes an XML-based format (e.g., SVG, RSS, or XHTML) without disabling external entities, an attacker can inject a malicious entity that reads local files (e.g., file:///etc/passwd), performs SSRF to internal endpoints, or triggers a denial of service (e.g., Billion Laughs attack). In link previews, this commonly occurs when fetching SVG images or XML feeds that the server parses to extract metadata.
7.DNS Rebinding:
A domain is validated as safe (public IP), but after validation the DNS is changed to resolve to an internal address, tricking the fetcher into attacking internal hosts. Impact: Bypasses IP blocklists, enables SSRF on previously validated domains. Mitigation: Pin the IP after initial DNS resolution; reject any domain where the resolved IP changes between validation and fetch; use a DNS resolver that disables rebinding and do this manual (IP Pinning Method For Preparing Important Security Measurement) (e.g., by ignoring TTL=0).
Secure Implementation Architecture
A secure link preview system must be designed with defense in depth. The core principle: never trust the URL or its content.
High Level Design:
Role Of The DMZ:
A DMZ is a network segment isolated from both the internet and the internal network by two firewalls.
1) Why a DMZ for link previews?
-
The preview fetcher must initiate connections to arbitrary user‑controlled URLs — this is inherently dangerous.
-
If the fetcher is compromised (e.g., via a buffer overflow in an HTML parser), the attacker lands in the DMZ, not on your core application or database servers.
-
From the DMZ, lateral movement to the internal network is blocked by firewall rules (only established/related responses allowed back, no new connections).
Application‑Level Defenses (Inside the Fetcher):
Even with a DMZ, the fetcher must implement strict controls:
1.URL Validation & Scheme Whitelist:
-
Allow only http:// and https://.
-
Reject file://, javascript://, data://, gopher://, ftp://.
-
Normalize and re‑validate after each redirect.
2.Block Internal IPs & Reserved Ranges:
-
Deny requests to: 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, ::1, fc00::/7.
-
Use a DNS resolver that rejects internal hostnames (localhost, internal‑api).
3.Timeouts & Size Limits:
-
Connection timeout: 5 seconds
-
Read timeout: 10 seconds total
-
Max download size: 2 MB for HTML, 10 MB for images (then compress/resize)
-
Max redirects: 5 (re‑validate each target)
-
Disable compression (gzip, deflate) to avoid decompression bombs.
4.Safe HTTP Fetching:
-
Use HEAD request first to check Content‑Length and Content‑Type.
-
Never send cookies, authentication headers, or custom User‑Agent. Use (User‑Agent: LinkPreviewBot/1.0)
-
Ignore Set‑Cookie responses.
5.HTML & Metadata Sanitization:
-
Parse HTML with a non‑JavaScript parser (e.g., lxml with defusedxml, Go's html.Parse).
-
Extract only: og:title, og:description, og:image, twitter:card,
, first . -
Strip all scripts, event handlers, and CSS expressions.
-
Escape output: treat title/description as plain text, apply HTML escaping (< etc.) before embedding in JSON.
6.Caching:
-
Cache preview results keyed by normalized URL for 7–30 days.
-
Benefits: reduces load, prevents attackers from re‑probing internal IPs via the same URL, limits timing‑based privacy leaks.
Client Side Security
-
Never use innerHTML with preview data. Use textContent or framework‑safe bindings.
-
Proxy image URLs through your server (or use referrerpolicy="no-referrer" and crossorigin="anonymous").
-
Display the actual destination domain alongside the preview to mitigate phishing.
Additional Hardening
1) Rate limiting — Per user / per IP:
limit the number of preview requests to prevent abuse.
2) Logging & monitoring:
Log all fetched URLs (anonymized user ID) to detect scanning patterns. Ship logs to a SIEM.
3) Regular updates:
DMZ containers should be rebuilt weekly with the latest security patches.
4) Preventing SSRF with IP Obfuscation:
An attacker may bypass security filters by using different address representation formats. Many network libraries automatically convert these formats to numeric addresses, so validation must be done after full normalization.
Warning: Any host that is converted to any format of IP (IPv4/IPv6) after normalization should be rejected for preview generation.
Address formats that need to be recognized and normalized:
• 127.0.0.1 → 2130706433 :Decimal
• 127.0.0.1 → 0x7f000001 :Hex
• 127.0.0.1 → 0177.0.0.1 :Octal
• 127.0.0.1 → 127.1 :Partial
• 127.0.0.1 → ::ffff:127.0.0.1 :IPv6-mapped IPv4
• 0:0:0:0:0:0:1 → ::1 :IPv6 shorthand
5) Safely managing SVG files and preventing XXE:
SVG files can contain external references (
Implementation Requirements:
-
Safe Option: Block SVG completely — The easiest way is to reject any URL that ends in .svg or has a Content-Type of image/svg+xml.
-
Advanced Option: Sanitizer If SVG support is required:
a) Completely disable External Entities in the XML parser.
b) Strip all external references:
c) Validate SVG structure with a strict Schema.
d) Limit SVG file size.
6) Prevent Path Traversal in Internal URL Construction:
If parts of the destination URL are constructed from user input, an attacker may be able to redirect to sensitive endpoints by injecting ../.
Implementation Requirements:
-
Do not construct URLs with String Concatenation: Never construct URL path parts by concatenating a string from user input.
-
Path normalization: If path concatenation is required, use standard functions such as Path.normalize() and check the result.
-
Explicitly reject "..": Any user input containing ".." must be rejected before being used in URL construction.
-
Use Allowlist pattern: Instead of constructing a dynamic path, use a fixed set of allowed endpoints.
7) Security of internal communications between services:
-
Authentication: Use JWT with a specific Audience for inter-service requests.
-
Network Isolation: Fetch service in Private Subnet and access only from the chat service.
-
Encryption and Rate Limiting: Traffic over HTTPS and request rate limiting.
8) Message processing flow and behavior:
-
Get the link from the user's message.
-
Apply security filters (SSRF, DNS Rebinding, Parser Confusion, etc.).
-
If the initial filters pass, the request is forwarded asynchronously to the Fetch service.
-
On success: After extracting and refining the metadata, a message edit request is sent to attach the preview card.
-
On any error or blocking: No error, warning, or status message is displayed to the user. The message remains as plain, clickable text.
Key point: The default behavior is "silent." The user should not know that the preview was not generated — this approach both preserves the user experience and does not provide information to the attacker.
Final Implementation checklist
-
Limit protocol acceptance to http and https only.
-
Any host that is converted to an IP format after normalization is rejected for preview.
-
All sensitive IP ranges and internal domain patterns (such as *.cluster.local) are blacklisted.
-
All A/AAAA records returned from DNS are checked, not just the first one.
-
Redirect tracking is disabled in the HTTP client.
-
Network connections are established directly to the verified IP (IP Pinning).
-
Response download size is limited to just enough to extract metadata.
-
Connection and data read timeouts are set to short values.
-
Use a standard parser throughout the flow and do not perform reparsing after validation.
-
Control characters (Tab, Newline, Null) are definitely detected and rejected.
-
Every URL extracted from the HTML response (images, favicon…) should go through the entire validation pipeline again.
-
The extracted values should be sanitized before being sent to the client.
-
In outbound requests, sensitive headers (Authorization, Cookie, X-Forwarded) should be stripped.
-
SVG files should be either blocked or processed with a secure sanitizer and external entity deactivation.
-
Avoid building URLs with String Concatenation and user input; Canonicalize paths and ".." should be rejected.
-
The service should communicate with a dedicated token and be encrypted.
-
If the preview fails, the message should remain in plain text without any notification.
Validation Against Attack Vectors
Real‑World Precedent: Telegram & Signal
Telegram's link preview system:
-
Uses a separate bot (@preview) running in isolated infrastructure.
-
Metadata is fetched server‑side, sanitized, and cached.
-
Clients render previews as plain text (no HTML).
Signal's approach:
-
Previews are generated client‑side by default (privacy preserving).
-
For high‑security mode, previews can be disabled entirely.
Both demonstrate that automatic unfurling is a design choice with trade‑offs. For maximum security, consider allowing users to disable previews globally or requiring an explicit click to generate a preview.
Conclusion
The best way to implement link previews securely is a defense‑in‑depth architecture:
-
Place the preview fetcher in a DMZ with strict firewalls preventing inbound internet access and outbound connections to internal networks.
-
Apply application‑level controls: whitelist schemes, block private IPs, enforce timeouts and size limits, sanitize all metadata, and cache results.
-
Never trust user input — treat every URL as hostile.
-
Render safely on the client — use plain text, not HTML.
-
Monitor and log all fetching activity.
This combination stops SSRF, DoS, XSS, and data exfiltration attacks even if the fetcher software contains unknown vulnerabilities. While a DMZ adds operational complexity, it is the only way to ensure that a compromised preview service cannot pivot to internal assets. For chat applications handling sensitive data, this architecture is non‑negotiable.
References
- CVE‑2022‑25876 (link-preview-js npm package)
https://www.miggo.io/vulnerability-database/cve/CVE-2022-25876
-
CVE-2023–5969(Denial of Service via Link Preview in /api/v4/redirect_location) https://cve.imfht.com/detail/CVE-2023-5969?lang=en
-
CVE‑2025‑11987 (WordPress Visual Link Preview) https://www.incibe.es/index.php/en/incibe-cert/early-warning/vulnerabilities/cve-2025-11987
-
CVE‑2018‑20436 (Telegram Secret Chat) https://vi.loginsoft.com/cve/CVE-2018-20436?utm_source=loginsoft&utm_medium=article&utm_id=M9IJGMpHsK
-
OWASP SSRF Prevention Cheat https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
Happy Hacking, Special thanks for reading. by https://x.com/0X23XO