How DNS Rebinding Turns Localhost Into an Open Door

DNS rebinding is a browser-based attack that breaks the trust developers place in “localhost.” The premise is simple: a malicious webpage convinces the browser that its own origin now lives at a private IP address, and from that point on, scripts on the page can talk to local services as if they were same-origin resources. The technique is not new, but it remains a blind spot in many threat models.

To understand the attack, you need to start with the same-origin policy (SOP). Introduced by Netscape in 1995, SOP is the rule that scripts from one origin cannot read data from another origin. An origin is defined by the combination of protocol, hostname, and port. A mismatch in any of the three means a different origin. For a page served from https://www.somedomain.com/sub/page.html, the origin comparisons look like this:

URLOutcomeReason
https://www.somedomain.com:81/sub/page.htmlDifferentThe port 81 doesn’t match 443 (the default for https)
https://somedomain.com/sub/page.htmlDifferentExact www.somedomain.com match is required
http://www.somedomain.com:443/sub/page.htmlDifferentThe schema (protocol) HTTP doesn’t match HTTPS
https://www.somedomain.com/admin/login.htmlSameOnly the path differs

SOP is meant to stop arbitrary websites from reading your webmail or other sensitive content. But it assumes that a hostname resolves to a stable address. That assumption fails when DNS answers change underneath the browser.

The Mechanics of the Attack

Developers often assume that a service listening on 127.0.0.1 or a private LAN address is unreachable from the outside. That is true at the network layer, but it ignores the browser’s role as a proxy. The browser running on the victim’s machine can reach those addresses, and DNS rebinding tricks the browser into making cross-origin requests to them.

Here is how it works. An attacker controls a domain such as somesite.com and the DNS server that resolves it. The DNS server initially answers with a public IP address, so the victim’s browser loads content from the attacker’s site normally. The attacker then changes the DNS response to point somesite.com at a local or private address, such as 127.0.0.1 or 192.168.0.1. The JavaScript already loaded from somesite.com keeps running, and all subsequent requests it makes to that same hostname are now routed to the rebounded address. Because the browser still sees the requests as belonging to the somesite.com origin, documents served from the local IP are treated as same-origin. The attacker’s script can therefore read responses from any local web application that answers on that address and port.

There are limitations. If the local service requires authentication, the browser will not attach cookies or session credentials for that service, because the origin is still the attacker’s domain. The attacker also has to match the port of the target service, since port is part of the origin definition. Nonetheless, the attack works against any unauthenticated local endpoint, and it can also reach services on corporate intranets if the victim has active VPN routes.

Browser Defenses Are Inconsistent

Browsers do cache DNS responses, which makes rebinding harder but not impossible. The Local Network Access specification (formerly CORS-RFC1918) is a draft W3C proposal that segments address space into loopback, local, and public ranges. It closes several rebinding paths but leaves others open, including the non-routable 0.0.0.0 address, which still works on Linux and macOS. The practical outcome is that rebinding success depends heavily on the browser and operating system combination. That unreliability leads many to dismiss it, but tooling such as Tavis Ormandy’s Simple DNS Rebinding Service and NCCGroup’s Singularity of Origin makes the attack automatable.

A Real Vulnerability: Deluge WebUI

An actual case illustrates the danger. The Deluge BitTorrent client, fixed in v2.2.0, shipped a WebUI component with a path traversal in an unauthenticated endpoint. The WebUI is meant to be a local convenience, often started on boot or run permanently on a home server, so it was a realistic rebinding target.

def render(self, request):
	log.debug('Requested path: %s', request.lookup_path)
	lookup_path = request.lookup_path.decode()
	for script_type in ('dev', 'debug', 'normal'):
		scripts = self.__scripts[script_type]['scripts']
		for pattern in scripts:
			if not lookup_path.startswith(pattern): # <-- [1]
				continue

			filepath = scripts[pattern]
			if isinstance(filepath, tuple):
				filepath = filepath[0]

			path = filepath + lookup_path[len(pattern) :] # <-- [2]

			if not os.path.isfile(path):
				continue

			log.debug('Serving path: %s', path)
			mime_type = mimetypes.guess_type(path) # <-- [4]

			request.setHeader(b'content-type', mime_type[0].encode()) # <-- [5]
			with open(path, 'rb') as _file: # <-- [3]
				data = _file.read()
			return data

The vulnerable /js endpoint exists to serve JavaScript files to the UI and therefore does not require authentication. The code validates that request.lookup_path starts with a known keyword, but that check can be bypassed with a traversal sequence like /js/known_keyword/../.... The path is then concatenated and used to read a file from disk. A call to mimetypes.guess_type imposes a practical constraint: the file read succeeds only if its MIME type is recognized; otherwise an exception is raised when the response header is set.

That constraint still allows arbitrary file disclosure for any file with a known MIME type. Deluge stores its configuration in files with a .conf extension, which mimetypes.guess_type classifies as text/plain. A request to /js/deluge-all%2F..%2F..%2F..%2F..%2F..%2F..%2F.config%2Fdeluge%2Fweb.conf exposes the WebUI admin password as a SHA1 hash with salt, along with any sessions. Sessions are written to disk only at shutdown, and they expire after an hour by default, so finding a valid one is a gamble. The password hash is the more reliable route. Since Deluge does not use a slow password hashing algorithm, short or simple passwords can be brute forced quickly. Once authenticated, an attacker can chain the known exploit from CVE-2017-7178 to download, install, and execute a malicious plugin through the /json Web API.

Exploitation in Practice

If Deluge WebUI is exposed externally, exploitation is straightforward. But even a local-only setup is reachable via DNS rebinding, because the vulnerable endpoint requires no authentication. On browsers that implement Local Network Access, the attacker falls back to the 0.0.0.0 bypass to reach the loopback service.

An attack proceeds roughly as follows. The victim visits a malicious page that loads multiple iframes, each fetching http://sub.somesite.com:8182/attack.html. The port in the URL must match the port of the target service—8112 by default for Deluge WebUI—to satisfy same-origin requirements. The attacker’s DNS server alternates between 0.0.0.0 and the real server IP, using a very low TTL. When the response points to the real IP, the fetched script begins probing for the traversal endpoint. Once the DNS cache expires and the name resolves again, the script attempts to read the configuration file from the local service and exfiltrates it. A full working example is documented in the GitHub advisory.

Practical Defenses

  • HTTPS nullifies rebinding. Once a TLS session is established for the attacker’s domain, the browser validates the certificate against the hostname. When the DNS answer changes to a local address, a new session fails because the local service’s certificate does not match the domain.
  • Strong authentication is a reliable stopgap. Rebinding does not forward cookies for the target service, so a local application that requires a login is far less exposed than an unauthenticated one—even over plain HTTP.
  • Validate the Host header. A rebinding request arrives with the attacker’s hostname in that header. Deny requests whose Host value is not on an explicit allow list of expected names.

DNS rebinding is a pointed reminder that “runs locally” is not a security boundary. A service bound to loopback or a LAN interface is still reachable through the browser of anyone who visits a malicious page. Permanent local web apps without authentication or TLS are the highest risk. Treat DNS rebinding as part of the threat model, enforce authentication on every service, and validate the Host header before trusting any request.