=== modified file 'src/acl/DestinationIp.cc'
--- src/acl/DestinationIp.cc	2009-07-12 22:56:47 +0000
+++ src/acl/DestinationIp.cc	2011-06-20 10:24:32 +0000
@@ -37,6 +37,8 @@
 #include "acl/DestinationIp.h"
 #include "acl/FilledChecklist.h"
 #include "HttpRequest.h"
+// for Config.*
+#include "structs.h"
 
 char const *
 ACLDestinationIP::typeString() const
@@ -48,6 +50,17 @@
 ACLDestinationIP::match(ACLChecklist *cl)
 {
     ACLFilledChecklist *checklist = Filled(cl);
+
+    // Bug 3243: CVE 2009-0801
+    // Bypass of browser same-origin access control in intercepted communication
+    // To resolve this we will force DIRECT and only to the original client destination.
+    // In which case, we also need this ACL to accurately match the destination
+    if (Config.onoff.client_dst_passthru && checklist->request &&
+            (checklist->request->flags.intercepted || checklist->request->flags.spoof_client_ip)) {
+        assert(checklist->conn != NULL && checklist->conn->clientConnection != NULL);
+        return ACLIP::match(checklist->conn->clientConnection->local);
+    }
+
     const ipcache_addrs *ia = ipcache_gethostbyname(checklist->request->GetHost(), IP_LOOKUP_IF_MISS);
 
     if (ia) {

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2011-06-20 08:51:32 +0000
+++ src/cf.data.pre	2011-06-20 09:50:40 +0000
@@ -1803,6 +1803,36 @@
 
 DOC_END
 
+NAME: client_dst_passthru
+TYPE: onoff
+DEFAULT: on
+LOC: Config.onoff.client_dst_passthru
+DOC_START
+	With NAT or TPROXY intercepted traffic Squid may pass the request
+	directly to the original client destination IP or seek a faster
+	source.
+	
+	This option (on by default) prevents cache_peer and alternative DNS
+	entries being used on intercepted traffic. Both of which lead to
+	the security vulnerability outlined below.
+	
+	SECURITY WARNING:
+	
+	This directive should only be disabled if cache_peer are required.
+	
+	As described in CVE-2009-0801 when the Host: header alone is used
+	to determine the destination of a request it becomes trivial for
+	malicious scripts on remote websites to bypass browser same-origin
+	security policy and sandboxing protections.
+	
+	The cause of this is that such applets are allowed to perform their
+	own HTTP stack, in which case the same-origin policy of the browser
+	sandbox only verifies that the applet tries to contact the same IP
+	as from where it was loaded at the IP level. The Host: header may
+	be different from the connected IP and approved origin.
+
+DOC_END
+
 COMMENT_START
  SSL OPTIONS
  -----------------------------------------------------------------------------

=== modified file 'src/forward.cc'
--- src/forward.cc	2011-06-20 09:13:51 +0000
+++ src/forward.cc	2011-06-20 09:51:21 +0000
@@ -116,7 +116,24 @@
     // Otherwise we are going to leak our object.
 
     entry->registerAbort(FwdState::abort, this);
-    peerSelect(&serverDestinations, request, entry, fwdPeerSelectionCompleteWrapper, this);
+
+    // Bug 3243: CVE 2009-0801
+    // Bypass of browser same-origin access control in intercepted communication
+    // To resolve this we must force DIRECT and only to the original client destination.
+    if (Config.onoff.client_dst_passthru && request &&
+            (request->flags.intercepted || request->flags.spoof_client_ip)) {
+        Comm::ConnectionPointer p = new Comm::Connection();
+        p->remote = client->local;
+        p->peerType = HEIR_DIRECT; // TODO: make a special type for this?
+        getOutgoingAddress(request, p);
+        serverDestinations->push_back(p);
+
+        // destination "found". continue with the forwarding.
+        startConnectionOrFail();
+    } else {
+        // do full route options selection
+        peerSelect(&serverDestinations, request, entry, fwdPeerSelectionCompleteWrapper, this);
+    }
 }
 
 void

=== modified file 'src/structs.h'
--- src/structs.h	2011-05-15 08:42:17 +0000
+++ src/structs.h	2011-06-20 09:32:03 +0000
@@ -436,6 +436,7 @@
         int WIN32_IpAddrChangeMonitor;
         int memory_cache_first;
         int memory_cache_disk;
+        int client_dst_passthru;
     } onoff;
 
     int forward_max_tries;


