A dns rebinding attack is a trick where a web page you open in your browser quietly turns into a client for a device on your own home or office network. The page is served from a name the attacker controls, say rebind.acmeattacker.com, and your browser treats every request to that name as belonging to one origin. The attacker also controls the DNS server for that name, so a moment after the page loads they change the answer. The same name that first resolved to a public server now resolves to a private address like 192.168.1.1 or 127.0.0.1. Your browser keeps thinking it is talking to the same origin, because the hostname never changed, and the attacker’s JavaScript starts speaking directly to your router, your media server, or a service bound to localhost that was never meant to face the internet. This post walks the mechanism one step at a time: why the same origin policy trusts the hostname, how a short DNS time to live lets the attacker swap the IP underneath it, why DNS pinning only partly closes the gap, the answer tricks attackers use, the real devices this has hit, and the defenses that actually hold.
Why the browser trusts a name it cannot pin down
The same origin policy is the rule that keeps one site’s JavaScript from reading another site’s data. Two pages share an origin when their scheme, host, and port all match. A script on https://app.acmenotes.com can read responses from https://app.acmenotes.com and is blocked from reading https://api.bank.example. The host comparison is a string comparison on the hostname. As the MDN same origin policy reference describes it, origin is defined by scheme, host, and port, and the host part is the textual name. Nowhere in that comparison does the browser ask which IP address the name currently resolves to.
That choice is deliberate and mostly reasonable. A single hostname legitimately moves across IP addresses all the time. Load balancers rotate backends, content networks return the nearest edge, failover swaps a dead server for a live one. If the same origin policy were pinned to an IP address, ordinary sites would break every time DNS handed back a different answer. So the policy trusts the name and assumes the name keeps meaning the same thing for the life of the page.
It is worth being precise about what the origin actually is, because the whole attack lives in the definition. An origin is the triple of scheme, host, and port. The host is a registered domain name or an IP literal, and when it is a name, the browser stores and compares the name itself. The browser does resolve that name to an address in order to open a socket, but the resolved address is an implementation detail of the network layer, not part of the security identity. Two requests to https://rebind.acmeattacker.com are same origin with each other by definition, no matter what each one resolved to at the moment it was sent. The attacker is not breaking the comparison. They are feeding it two different machines under one honest name.
DNS is the part of the system that turns a name into an address, and it was built to be changeable on purpose. A record carries a time to live, the number of seconds a resolver may cache the answer before it has to ask again. Set that number to one second and you have told every resolver on the path that this answer expires almost immediately. The attacker who runs the authoritative DNS server for their own domain decides that number. They can answer one way now and a completely different way a second later, and the protocol considers both answers correct.
Put those two facts side by side and the gap appears. The browser fixes the origin on the name. DNS lets the attacker change what the name points at. The browser never rechecks.
The time of check versus time of use gap
The cleanest way to see dns rebinding is as a time of check to time of use bug, the classic shape where a system validates something once and then relies on that validation after the thing has changed. Here the check is the initial DNS lookup and the same origin decision that rides on it. The use is every later request the page makes to that same hostname.
Walk the sequence. The victim visits rebind.acmeattacker.com. Their browser asks the attacker’s DNS server for the address and gets back a normal public IP, say the attacker’s own web server, with a time to live of one second. The page loads, the malicious script runs, the origin is now fixed on that hostname. So far nothing is unusual and nothing private has been touched.
The script then waits, or makes a request that it knows will force a fresh lookup once the one second cache entry expires. The browser asks the attacker’s DNS server again. This time the answer is 192.168.1.1, the victim’s own router. From the browser’s point of view nothing about the origin has changed. The scheme is the same, the host string is the same, the port is the same. So it sends the request, including any work the script wants done, straight to the router. The check happened against the public server. The use lands on the private one. The window between them is the whole attack.
The reason the attacker bothers with this dance, rather than just pointing their page at 192.168.1.1 directly, is that the same origin policy would stop the direct approach cold. A page served from https://rebind.acmeattacker.com cannot read responses from http://192.168.1.1, because those are plainly different origins. The browser would let the request go out but hide the response from the script, which is useless to the attacker. Rebinding exists precisely to make the private address wear the attacker’s hostname, so the response comes back to a script that is allowed to read it. The attacker is borrowing the victim’s own browser as a proxy that sits inside the network and, crucially, is trusted to read what it gets back.
What the attacker needs from the victim is almost nothing. There is no exploit of the browser, no malware, no breached account. The victim only has to open a tab, which an attacker arranges with an advertisement, a link, or any embedded frame on a page the victim already visits. The page can keep the victim busy with ordinary looking content while the script quietly cycles through internal addresses in the background. By the time anything is noticeable, the requests have already been made and the responses already read.
The browser never lied about the origin. The origin simply stopped meaning what it meant at the instant the browser decided to trust it.
DNS pinning and why it is incomplete
Browsers noticed this years ago and added a countermeasure called DNS pinning. The idea is simple. Once the browser has resolved a hostname and started using it, hold onto that first IP address for the lifetime of the page even if the DNS record’s time to live says the answer has expired. If the browser refuses to follow the rebind, the second lookup never reaches the router, and the attack dies.
Pinning helps, but it was never a complete fix, for reasons that are structural rather than bugs to be patched away. The browser cannot pin forever. A page can stay open for hours, connections drop and get reestablished, and a pin that lasted indefinitely would break legitimate failover. So pins expire. An attacker who is willing to wait, or who can make the original connection fail, gets a fresh lookup and a fresh chance to rebind.
Pinning also lives in only one place. The browser may pin, but it is not the only component resolving names and caching answers. The operating system has its own resolver cache, the local network may run its own, and these layers do not coordinate their pins. An answer that one layer considers expired another may serve fresh. The gaps between independent caches are exactly where a patient rebind slips through.
There is a deeper limit too. Pinning binds a name to an address inside one browser process for one page session, but the attacker controls time. A rebinding script does not have to win in the first second. It can hold the tab open, throttle its own requests, and simply outlast whatever pin the browser is willing to maintain. The economics here favor the attacker the same way they do elsewhere in security. The defender has to keep the pin perfect across every cache and every reconnect. The attacker only needs the pin to lapse once.
Multiple A records and the 0.0.0.0 trick
Attackers found ways to make rebinding faster and more reliable than waiting on a cache to expire. One is to return multiple A records in a single answer. The attacker’s DNS server replies with two addresses for the name at once, their public server and the target’s private address. The browser connects to the public one first because that is where the page is served. Then the attacker makes their own server stop answering on that port. The browser, holding a name that still has a valid private address in the same record set, fails over to the private address without any new lookup at all. The rebind happens inside one cached answer, so pinning on the time to live buys nothing.
A related family of tricks abuses how some systems treat special addresses. The address 0.0.0.0 is not a normal destination. On many operating systems a connection to 0.0.0.0 is routed to localhost, so a service bound to 127.0.0.1 can be reached through it. This has been the basis of a long running class of issues, often discussed as the 0.0.0.0 problem, where a public page reaches a service the developer believed was safely bound to localhost only. Combine that with rebinding and a service that listens on the loopback interface, assuming nothing on the wider network can talk to it, is suddenly reachable from a tab the user opened by accident.
What dns rebinding actually reached in the wild
This is not theoretical. The most thoroughly documented modern survey is the NCC Group researcher Brannon Dorsey’s writeup, Attacking Private Networks from the Internet with DNS Rebinding, which walked the full chain against consumer hardware and named the devices. The pattern across all of them is the same. Each device exposed an HTTP control interface on the local network with no authentication, on the unstated assumption that only software already inside the home would ever reach it.
Google Home and Chromecast devices exposed an undocumented REST API on port 8008 that required no authentication and could launch apps, play content, reboot the device, and scan for nearby WiFi networks, which in turn enabled rough geolocation of the home. Roku devices exposed an External Control API on port 8060 with the same no authentication shape, tracked as CVE-2018-11314. Sonos WiFi speakers exposed debugging endpoints and a UPnP server that allowed network reconnaissance commands, tracked as CVE-2018-11316. Radio Thermostat CT50 and CT80 units exposed a completely unauthenticated control API, CVE-2018-11315, where the demonstrated impact was setting the temperature in a victim’s home to 95 degrees. WiFi routers were the highest value target, because the same UPnP and admin interfaces let an attacker rewrite the router’s own DNS server or add port forwarding rules, which turns a single accidental page view into a lasting foothold on the whole network.
The Transmission case and a real CVE
The starkest single example is CVE-2018-5702, found by Tavis Ormandy of Google Project Zero in the Transmission BitTorrent client. Transmission exposes a remote procedure call interface over HTTP for its web and desktop front ends. Its access control relied on a custom header, X-Transmission-Session-Id, which is not on the browser’s list of forbidden headers and so could be obtained and replayed by a malicious page. Through a rebinding attack a web page could reach the local Transmission daemon and issue RPC commands. As Ormandy described the impact, an attacker could set script-torrent-done-enabled and have an arbitrary command run when a torrent finished, or set download-dir to the user’s home directory and upload a torrent named to overwrite a file like .bashrc. That is remote code execution reached from an ordinary browser tab. Ormandy reported it and supplied a fix the following day, which landed as a Host header validation patch on the Transmission project. The fix is worth noting because it points straight at the right defense.
Rebinding reaches more than home gadgets
The technique generalizes to anything that trusts the network it sits on. Internal admin panels that skip authentication because they are only reachable on a corporate subnet are reachable through a rebind from any employee’s browser. In cloud environments the same idea targets the instance metadata service, the link local endpoint at 169.254.169.254 that hands out credentials to a workload. A rebind that lands on that address from inside a victim’s network or browser context is closely related to the broader class of server side request forgery, where a trusted client is steered into making a request it should never make. The rebind is the steering mechanism. The metadata service is the prize.
Finding the target from inside the browser
Before an attacker can rebind onto a useful service they have to know it is there, and the same browser that runs their script can also do the scouting. A script can try to load resources from a range of private addresses and ports and watch how long each attempt takes or whether it errors. A closed port fails fast, an open one behaves differently, and the timing alone leaks which internal hosts and services are alive. The private IP space is small and predictable. Home networks cluster on 192.168.0.0/16 and 10.0.0.0/8, routers sit on the first usable address, and well known services answer on well known ports. The attacker does not need to guess much.
Once a live service is mapped, the rebind is aimed at exactly that address and port, and the generic page becomes a targeted client. This is why rebinding pairs so naturally with browser based port scanning. The scan tells the attacker where to point the rebind, and the rebind turns a discovered service into one the script is allowed to read from. Neither half requires anything beyond an open tab.
A worked example on Acme Notes
Make it concrete with our invented app. Suppose Acme Notes ships a small desktop helper that runs a local sync agent, listening on 127.0.0.1:7000 to talk to the Acme Notes app at app.acmenotes.com. The team bound it to localhost on the reasonable belief that only software already on the machine could reach it, so they did not add authentication to its control endpoint. A user installs the helper and later, on an unrelated tab, opens a page that an attacker controls.
That page is served from sync.acmeattacker.com, resolves first to the attacker’s public server, and loads a script. The script waits for the one second pin to lapse, the name rebinds to 127.0.0.1, and now the script is talking to the local sync agent under a hostname the browser trusts. Because the agent never checked who was calling, it answers, and the script can read sync state, change settings, or point the agent at a server the attacker runs. The takeaway is not that Acme Notes wrote bad code. It is that binding to localhost was treated as authentication when it is only a filter on connection origin, and rebinding is built specifically to defeat that filter.
Defenses that actually hold
Because rebinding works by changing the IP under a trusted name, the durable defenses are the ones that stop trusting the network position and start checking something the attacker cannot forge.
Validate the Host header
This is the single most important server side fix, and it is the one the Transmission patch used. A service that is meant to answer only for localhost or its own hostname should inspect the Host header on every request and reject anything that does not match an allowlist of expected values, returning a 403 Forbidden. When the rebind lands, the browser still sends Host: rebind.acmeattacker.com, because that is the name in the address bar. The service sees a host it does not serve and refuses. The attacker cannot change the Host header to a forged value from JavaScript, because the browser sets it from the URL. This check costs almost nothing and defeats the core of the attack.
Require real authentication, not network position
A service that demands a credential the attacker’s page does not have is safe from rebinding even if the request reaches it. Binding to 127.0.0.1 is not authentication. It is a filter on where connections may originate, and rebinding is precisely a way to originate from there. Bind to localhost if you like, but also require an authenticated session, and do not rely on a header that scripts can obtain and replay. The whole Transmission issue was a custom header standing in for real access control.
Filter private answers at the resolver
A DNS resolver can refuse to return private addresses in answers for public names. If a name under a public domain tries to resolve to 192.168.x.x, 10.x.x.x, 127.0.0.1, or the link local metadata address, the resolver drops or rewrites that answer, and the rebind never completes. Tools like dnsmasq and several home and enterprise resolvers offer exactly this rebinding protection, and some public resolvers strip private ranges out of responses by default. It is a network level safety net rather than a per service fix, but it stops a large fraction of attacks before they reach any device.
Adopt Private Network Access in the browser
The browser platform itself is closing the gap. The Private Network Access specification, formerly known as CORS-RFC1918, restricts a public page from making requests into a private network unless the private service explicitly opts in with a CORS preflight. A request from a public origin to a private IP triggers a preflight that the target must answer with the right header, and an attacker’s router or media server will not. This shifts the default from quietly allowing public to private requests toward refusing them, which is exactly the assumption rebinding has always exploited.
The assumption that breaks
Underneath every variation of this attack sits one assumption. The same origin policy trusts the hostname, and it assumes the hostname keeps pointing at the same machine for as long as the page lives. That assumption is convenient and almost always true, which is why it survived. DNS was designed to let a name move between addresses, and the browser cannot tell a legitimate move from a malicious one, because both look like a name resolving to a new IP. The browser is not broken. It is honoring a contract that DNS never promised to keep.
So the defenses that last are the ones that stop deciding trust from where a request appears to come from. Check the Host header, demand a real credential, and refuse private answers for public names. Each of those replaces a trust in network position with a check the attacker cannot satisfy. The gap between what a component assumes about a name and what an attacker can actually arrange with DNS is the kind of flaw you find by asking what each layer trusts and why it keeps trusting it after the situation has moved, rather than by scanning for a known bad string. It is exactly the kind of assumption an autonomous researcher built to test assumptions is meant to catch. Learn more about that approach on our about page.
Frequently asked questions
What is DNS rebinding in simple terms?
It is an attack where a web page served from a hostname the attacker controls swaps that name’s IP address right after the page loads. The browser keeps treating requests as one origin because the hostname never changed, so attacker JavaScript can reach private services like a router or a localhost daemon. It works because the same origin policy compares the host as a name and never rechecks which IP that name currently resolves to.
Why does a short DNS TTL matter for the attack?
The time to live tells resolvers how many seconds they may cache an answer before asking again. The attacker sets it to about one second so the browser quickly performs a fresh lookup and receives a private address like 192.168.1.1 in place of the original public one. The result is a time of check to time of use gap, walked step by step in the NCC Group writeup Attacking Private Networks from the Internet with DNS Rebinding.
Has DNS rebinding led to a real vulnerability?
Yes. CVE-2018-5702 was a remote code execution flaw in the Transmission BitTorrent client found by Tavis Ormandy, where a page could reach the local RPC interface through a rebind and run commands. Researchers also documented unauthenticated control of Google Home, Chromecast, Roku, Sonos, and routers via the same technique. The Transmission fix added Host header validation to reject requests that do not match the expected name.
How do you defend against DNS rebinding?
Validate the Host header on every request and reject names you do not serve, since the browser still sends the attacker’s hostname after the rebind. Require real authentication instead of trusting that a request came from localhost or a private subnet, and have resolvers drop private IPs from answers for public names. Browsers are also restricting public to private requests through the Private Network Access specification, formerly CORS-RFC1918.
