When we built ProxyOrb, we faced a fundamental paradox at every design decision: a web proxy works by making the browser believe that third-party content is same-origin content. That is, by definition, tricking the browser's core security model. Yet modern browsers have spent fifteen years layering increasingly sophisticated defenses precisely against this kind of origin confusion.
This article examines that tension from first principles. If you are a security researcher, penetration tester, or browser security engineer who wants to understand how web proxies actually interact with the same-origin policy — not at a conceptual level, but at the level of HTTP headers, Chromium source code, and production engineering trade-offs — this is for you.
We will cover the SOP foundation, URL rewriting, CORS, CORB/CORP, COEP/COOP, Service Workers, iframes, and the security implications for both proxy operators and their users.
1. The Same-Origin Policy Foundation
The same-origin policy (SOP) is defined by a three-tuple: scheme + host + port. Two URLs are same-origin only if all three components match exactly. https://example.com:443 and http://example.com:80 are cross-origin despite pointing to the same server.
What is frequently misunderstood is what SOP actually prevents versus what it permits. SOP does not block:
- Loading images (
<img src>) across origins - Loading scripts (
<script src>) across origins - Loading stylesheets (
<link rel="stylesheet">) across origins - Embedding iframes across origins (though the embedded document's contents are isolated)
- Sending form submissions (
<form action>) across origins
What SOP does prevent is reading the response of cross-origin requests made via fetch() or XMLHttpRequest. The request goes out — the network round-trip happens — but the response body and headers are withheld from JavaScript running in a different origin.
This distinction matters enormously for web proxies. The proxy's entire job is to collapse two origins (the proxy server and the target server) into one, eliminating the cross-origin boundary. Once all resources appear to come from ProxyOrb - Free Web Proxy, the browser's SOP-based restrictions on reading responses simply do not apply.
The "legitimate space" that web proxies exploit is URL rewriting: instead of https://example.com/api/data, every request becomes https://proxyorb.com/api/data?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==. From the browser's perspective, this is a same-origin request. The SOP has not been bypassed — it has been rendered irrelevant by changing the apparent origin of all content.
2. ProxyOrb's URL Rewriting Architecture
To understand the security implications, you need to understand the encoding mechanism. ProxyOrb uses a URL parameter named __pot (proxy origin token) which contains the Base64-encoded target origin.
The __pot Parameter
The parameter __pot always encodes the origin (scheme + host, no path) of the target, not the full URL. This means https://example.com/some/deep/path?foo=bar and https://example.com/other/page both generate the same __pot value: aHR0cHM6Ly9leGFtcGxlLmNvbQ== (the Base64 encoding of https://example.com). The actual path and query string are preserved verbatim in the proxy URL's own path and query string.
When a user navigates to https://proxyorb.com/?__pot=aHR0cHM6Ly9leGFtcGxlLmNvbQ==, the gateway decodes it and reconstructs the original URL:
-- Gateway pseudocode: decoding the proxy request
function resolve_original_url(proxy_url):
pot_value = parse_query_param(proxy_url, "__pot")
if not pot_value:
return error("Missing origin token")
original_origin = base64_decode(pot_value)
-- e.g. "https://example.com"
validate_not_private_ip(original_origin) -- SSRF protection
-- Replace the proxy host with the target host, keep path/query intact
original_url = replace_origin(proxy_url, original_origin)
return original_url
The gateway then forwards the request to the real target server, rewriting the Origin header so the upstream server sees its own domain rather than the proxy domain:
-- Set outbound headers toward the target server
request.headers["Host"] = target_host
request.headers["Origin"] = target_origin -- e.g. "https://example.com"
-- Remove all internal proxy headers before forwarding
Client-Side URL Rewriting via Service Worker
The gateway handles the server side. The client side — rewriting URLs in HTML, JavaScript, and CSS responses so that all sub-requests continue through the proxy — is handled by a Service Worker.
The core transformation converts any URL encountered in page content to proxy format:
-- Service Worker pseudocode: toProxyURL()
function toProxyURL(originalUrl, currentPageUrl):
if isSameOrigin(originalUrl, currentPageUrl):
return originalUrl -- already proxy-origin, no rewrite needed
-- Extract path/query/hash from the original URL
-- Build a new URL rooted at the proxy origin
proxyPath = extractPathAndQuery(originalUrl)
potValue = base64encode(extractOrigin(originalUrl))
proxyUrl = proxy_origin + proxyPath + "?__pot=" + potValue
return proxyUrl
For example, https://cdn.example.com/bundle.js referenced inside a page being proxied becomes https://proxyorb.com/bundle.js?__pot=aHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20=.
This rewriting is comprehensive: it covers fetch(), XMLHttpRequest, <script src>, <img src>, WebSocket connections, and <link> tags. When every URL in the page points to the proxy origin, the browser never makes a cross-origin request — every request is same-origin by construction.
Recovering __pot Without Full Navigation
A subtle edge case arises with requests that originate from within a proxied page but lack the __pot parameter — for example, a relative fetch('/api/data') that fires before the Service Worker has rewritten the URL, or a request issued by a dynamically-injected script that bypassed the URL rewriter.
The Service Worker resolves the missing token via a cascading lookup:
-- Service Worker pseudocode: recovering the origin token
function resolveMissingPot(fetchEvent):
candidates = [
getUrlOfControlledTab(fetchEvent.clientId), -- most reliable
inferUrlFromFetchEvent(fetchEvent), -- from clientId / resultingClientId
fetchEvent.request.referrer, -- referrer header
]
for url in candidates:
pot = extractQueryParam(url, "__pot")
if pot: return pot
return null -- cannot recover; let the gateway handle or reject
The gateway has a parallel recovery path: if a request arrives without __pot but carries a Referer header pointing to a same-origin URL that does include __pot, the gateway extracts the token from the referer and attaches it to the current request. This handles navigation scenarios where the token was stripped by the page's own JavaScript before the gateway received the request.
3. CORS: The Explicit Cross-Origin Permission System
CORS (Cross-Origin Resource Sharing) was designed to let servers opt in to cross-origin access by sending specific response headers. From the proxy's perspective, CORS creates two distinct problems.
Problem 1: CORS Preflight Interception
When JavaScript running on a page makes a fetch() request with non-simple headers (e.g., Authorization, Content-Type: application/json), the browser sends an OPTIONS preflight request first. If the target server's preflight response does not include permissive CORS headers, the real request is blocked.
In ProxyOrb's architecture, the Service Worker intercepts all OPTIONS requests and answers them synthetically — before they even reach the gateway — returning a response that unblocks the real request:
-- Service Worker pseudocode: synthetic CORS preflight
function handlePreflight(request):
origin = request.headers["Origin"] or "*"
return Response(status=204, headers={
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Max-Age": "86400",
"Vary": "Origin",
})
At the gateway level, every proxied response receives equivalent CORS headers:
-- Gateway pseudocode: set CORS on outbound response
response.headers["Access-Control-Allow-Origin"] = original_origin
response.headers["Access-Control-Allow-Headers"] = "*"
response.headers["Access-Control-Allow-Credentials"] = "true"
Problem 2: Credentialed Requests
The combination of Access-Control-Allow-Credentials: true and a non-wildcard Access-Control-Allow-Origin is significant. CORS requires an explicit origin value (not *) whenever credentials are included. The Service Worker issues all outbound requests with credentials: 'include', so the gateway must echo back the exact requesting origin rather than a wildcard.
This means all cookies stored under proxyorb.com — accumulated from every target site the user has visited through the proxy — are sent on every proxied request. This is intentional (it maintains session state for logged-in sites), but it is also an important security consideration we discuss in Section 8.
The CORS Header Strip-and-Replace Pattern
A proxied response may carry CORS headers from the target server that are wrong from the browser's perspective (they reference the target origin, not the proxy origin). The Service Worker strips and replaces them:
-- Service Worker pseudocode: sanitize response headers
function sanitizeResponseHeaders(response):
headers = copy(response.headers)
-- Remove target-site directives that would confuse the browser
headers.delete("Content-Security-Policy")
headers.delete("Content-Security-Policy-Report-Only")
headers.delete("X-Frame-Options")
headers.delete("X-Content-Type-Options")
-- Replace with proxy-origin-correct CORS headers
headers.set("Access-Control-Allow-Origin", proxy_origin)
headers.set("Access-Control-Allow-Credentials", "true")
headers.set("Access-Control-Allow-Headers", "*")
headers.set("Vary", "Origin")
return headers
4. CORB and CORP: Chromium's Stricter Defenses
CORS operates on explicit opt-in from servers. Chromium added two mechanisms that are active by default, regardless of CORS configuration.
Cross-Origin Read Blocking (CORB)
CORB was introduced in Chrome 67 (2018) as part of the Spectre mitigations. The core insight: even if a cross-origin response's body is never read by JavaScript, the fact that it was fetched and decoded by the renderer process means it exists in that process's address space. Spectre-class attacks can then extract it via side channels.
CORB prevents certain cross-origin responses from ever entering the renderer process. Specifically, when a <script> tag or <img> tag fetches a cross-origin response and that response has a Content-Type of text/html, text/xml, or application/json, Chromium inspects the body (using a MIME-type sniffer defined in the CORB spec) and, if the type matches, replaces the response with an empty one before the renderer ever sees it.
For a web proxy, CORB would be catastrophic if requests were actually cross-origin. An API endpoint returning application/json fetched from a <script> tag would silently return empty. However, since ProxyOrb rewrites all URLs to be same-origin, CORB's cross-origin condition is never triggered — the browser never sees a cross-origin JSON response, because from its perspective, all responses come from proxyorb.com.
The one case where CORB matters is during the transition period before the Service Worker is fully registered and intercepting requests. If any request escapes URL rewriting during that window, CORB may block it. This race condition is why ProxyOrb also maintains a main-thread interceptor layer that patches XMLHttpRequest, fetch, and DOM attribute setters synchronously before any page JavaScript runs — providing a fallback during Service Worker startup.
It is worth noting that CORB has been partially superseded by Opaque Response Blocking (ORB), which Chromium is in the process of adopting. ORB refines the CORB rules to reduce false positives while maintaining the Spectre protections. The proxy compatibility implications are similar.
Cross-Origin Resource Policy (CORP)
CORP, defined in the Fetch spec, allows servers to declare that their resources should only be loaded by same-origin or same-site contexts:
Cross-Origin-Resource-Policy: same-origin
When Chromium encounters this header on a cross-origin sub-resource request, it blocks the response entirely. This is more aggressive than CORB — it applies regardless of content type and cannot be bypassed by MIME sniffing.
Again, since ProxyOrb's URL rewriting ensures all requests are same-origin from the browser's perspective, CORP headers from target servers do not trigger blocking. The gateway also strips these headers from responses defensively, handling any edge cases where a request slips through without URL rewriting.
The deeper issue with CORP is actually a case where the proxy architecture helps compatibility: if https://api.example.com and https://www.example.com are both being proxied, both map to the same proxy origin, so a fetch from one to the other is now genuinely same-origin — CORP restrictions no longer apply between them.
5. COEP and COOP: Cross-Origin Isolation
Starting in Chrome 92 (2021), access to SharedArrayBuffer — and by extension, high-resolution timers used for certain performance APIs — was restricted to pages that have opted into cross-origin isolation. This opt-in requires two response headers working in tandem.
Cross-Origin-Embedder-Policy (COEP)
Cross-Origin-Embedder-Policy: require-corp
When a page sends this header, the browser enforces that every sub-resource loaded by that page either:
- Is same-origin, OR
- Sends
Cross-Origin-Resource-Policy: cross-originexplicitly, OR - Has a permissive CORS response for the credentialed fetch
The problem for web proxies: if a target site sends COEP: require-corp on its main document, and that document is served through the proxy with the header preserved, the browser now demands that every sub-resource loaded by that page also opts in. Any resource that doesn't — and most won't — causes a network error.
Cross-Origin-Opener-Policy (COOP)
Cross-Origin-Opener-Policy: same-origin
COOP controls whether a page can share a browsing context group with cross-origin pages. When set to same-origin, a cross-origin navigation opens a new browsing context group, breaking window.opener references and postMessage channels between the page and any cross-origin openers.
For a proxy, COOP is less immediately destructive than COEP, but it still breaks sites that rely on cross-origin postMessage flows (OAuth popup flows being the most common example).
The Proxy Operator's Dilemma
This is the hardest trade-off we face at ProxyOrb:
Option A: Strip COEP and COOP from responses.
- Pro: Sub-resource loading works normally; the proxied page doesn't apply these restrictions.
- Con: We are removing security headers that the target site intentionally set. If the site was using cross-origin isolation to protect sensitive data from Spectre-class attacks, stripping these headers re-exposes that risk.
Option B: Preserve COEP and COOP.
- Pro: The target site's security intent is honored.
- Con: Any sub-resource that doesn't explicitly set
CORP: cross-originwill fail to load, breaking most complex web applications.
ProxyOrb's current strategy is Option A: the gateway strips Cross-Origin-Embedder-Policy and Cross-Origin-Opener-Policy from responses. This maximizes site compatibility. The security trade-off is consciously made: users of a web proxy are accepting that they are running content in an environment different from its intended deployment context.
Each new browser security mechanism follows a pattern: it is introduced as an opt-in (sites can send the header if they want protection), then gradually made default for new APIs, and eventually considered for mandatory enforcement. COEP followed this path: optional in Chrome 83, required for SharedArrayBuffer in Chrome 91. Sites that embed third-party content without coordination found their content broken. Web proxies compound this problem because they mediate third-party content by definition.
The browser security community is aware of this problem. The emerging Document-Isolation-Policy proposal aims to decouple process isolation from cross-origin isolation requirements, potentially making it possible to get Spectre mitigations without requiring all sub-resources to opt in. When that ships, proxy compatibility with isolation headers may improve.
6. Service Worker as the Browser-Side Trust Layer
The Service Worker is not merely an optimization — it is architecturally essential to ProxyOrb's security model. Here is why.
Registration Scope Binds to Origin
A Service Worker is registered with a scope that is always within the registering page's origin. When ProxyOrb registers its Service Worker, the scope is https://proxyorb.com/, meaning it intercepts every fetch from any page under that origin.
This is the fundamental reason why URL rewriting to same-origin works: once the SW is controlling a client, every network request from that client — regardless of what URL the JavaScript in the page tries to fetch — passes through the Service Worker first.
// Service Worker entry point
self.addEventListener('fetch', (event) => {
event.respondWith(handleProxyRequest(event))
})
The Interception Pipeline
When the Service Worker intercepts a request, it runs through several decision stages:
-- Service Worker pseudocode: request interception pipeline
function handleProxyRequest(fetchEvent):
request = fetchEvent.request
-- Stage 1: Synthetic CORS preflight (never hits the network)
if request.method == "OPTIONS":
return syntheticCORSResponse(request)
-- Stage 2: Pass through requests that shouldn't be proxied
if shouldBypass(request.url):
return originalFetch(request)
-- Stage 3: Ensure __pot is present; recover from context if missing
enrichedRequest = attachOriginToken(request, fetchEvent)
-- Stage 4: Forward to gateway
response = originalFetch(enrichedRequest)
-- Stage 5: Strip and replace security headers in the response
return sanitizeAndReturn(response)
Transparent Header Forwarding
One subtle challenge: the browser restricts JavaScript from setting certain "forbidden" request headers (Host, Origin, Referer, etc.) via the Fetch API. The Service Worker works around this by encoding restricted headers into a single custom passthrough header; the gateway then decodes and applies them before forwarding to the target server:
-- Pseudocode: encode browser-restricted headers for the gateway
function addPassthroughHeaders(request, outboundHeaders):
restricted = {}
for name, value in request.headers:
if name not in COMMON_ALLOWED_HEADERS:
restricted[name] = value
if restricted is not empty:
outboundHeaders["X-Proxy-Passthrough"] = json_encode(restricted)
-- Gateway side: decode and apply before forwarding upstream
function applyPassthroughHeaders(incomingHeaders):
encoded = incomingHeaders["X-Proxy-Passthrough"]
if encoded:
for name, value in json_decode(encoded):
request.headers[name] = value
request.headers.delete("X-Proxy-Passthrough")
Security Implications of SW as Trusted Intermediary
From a security perspective, the Service Worker occupies a privileged position: it can inspect, modify, and forge any request made from any page in its scope. For legitimate proxy use, this is the entire point. For a malicious proxy, this would be an extremely powerful attack surface.
This is why the trustworthiness of the Service Worker script itself is paramount. ProxyOrb serves the interceptor script from its own origin over HTTPS with strict cache controls. If an attacker could inject a modified Service Worker, they could intercept all traffic from affected users — not just proxy traffic, but any request from pages under that origin.
7. iframes: The Frame-Ancestors Problem
iframes represent a distinct challenge from regular sub-resources because they involve a nested browsing context with its own navigation, its own SOP boundary, and its own set of embedding restrictions.
X-Frame-Options and frame-ancestors
Two mechanisms prevent pages from being embedded in iframes:
Legacy: X-Frame-Options: DENY or X-Frame-Options: SAMEORIGIN
Modern: Content-Security-Policy: frame-ancestors 'none' or frame-ancestors 'self'
When the gateway proxies a target page that sends either of these, the page cannot be embedded in an iframe under the proxy origin. Since X-Frame-Options: SAMEORIGIN references the target origin (example.com), and the proxy serves the page from proxyorb.com, the browser's same-origin check fails.
The proxy must strip these headers from proxied responses and replace the CSP with a permissive version:
-- Gateway pseudocode: override embedding-restrictive headers
response.headers.delete("X-Frame-Options")
response.headers.delete("Content-Security-Policy")
response.headers.delete("Content-Security-Policy-Report-Only")
-- Set a permissive replacement that allows the proxy to embed content
response.headers["Content-Security-Policy"] =
"upgrade-insecure-requests; frame-ancestors 'self'; " +
"default-src * data: blob: about: ws: wss: 'unsafe-inline' 'unsafe-eval'"
Iframe Interception and Script Injection
Embedded iframes present a second problem: their content is loaded from the proxy, but the iframe's browsing context does not automatically have the Service Worker or the main-thread interceptor active. If the proxied page creates an <iframe src="https://widget.example.com/...">, that iframe URL must also be rewritten to the proxy format, and the proxy's interceptor scripts must be injected into the iframe's document.
The iframe interceptor operates at two levels:
Level 1 — Prototype patching (catches programmatic iframe creation):
-- Pseudocode: intercept iframe src assignment
override HTMLIFrameElement.prototype.src setter:
if value is not already a proxy URL:
value = toProxyURL(value) -- rewrite to proxy format
call original setter(value)
scheduleProxyInjection(this) -- inject interceptor into iframe document
Level 2 — MutationObserver fallback (catches DOM-inserted iframes):
-- Pseudocode: observe DOM for dynamically added iframes
observer = new MutationObserver(mutations):
for mutation in mutations:
for node in mutation.addedNodes:
if node is an <iframe>:
rewriteSrcIfNeeded(node)
injectProxyScript(node)
observer.observe(document, { childList: true, subtree: true })
The sandbox Attribute Problem
The HTML sandbox attribute restricts what an iframe can do: sandbox="allow-scripts allow-same-origin" controls script execution, form submission, cross-origin access, etc. For proxy injection to work, the iframe needs to run scripts and have access to the parent's proxy context.
The allow-same-origin token is particularly nuanced: when present along with allow-scripts, it defeats the sandbox's origin isolation — the iframe runs with the origin of the embedding page. When absent, the iframe gets a unique opaque origin, which would break proxy script injection entirely.
ProxyOrb's current approach for sandbox attributes is to remove the sandbox attribute entirely before injecting the proxy script:
-- Pseudocode: handle sandbox attribute before proxy injection
function handleSandboxedIframe(iframe):
if iframe.hasAttribute("sandbox"):
-- Remove so the proxy can inject scripts and access contentWindow
iframe.removeAttribute("sandbox")
injectProxyScript(iframe)
This is a significant security trade-off: the sandboxing was intentionally placed by the original site to restrict the embedded content's capabilities. Removing it expands what that content can do. It is the kind of decision that is invisible to end users but materially affects the security posture of the proxy session.
8. Security Implications for Proxy Operators
The Attack Surface Landscape
When users browse through ProxyOrb, several categories of sensitive data flow through the proxy's origin:
Session Cookies: Since all target sites are proxied through proxyorb.com, cookies are stored under that origin. A user's authenticated sessions with their bank, email, and social media are all cookies under a single domain. The Service Worker's credentials: 'include' means these cookies accompany every proxied request.
Referer Headers: The Referer header sent to upstream servers reveals what page the user was viewing. The proxy carefully strips its own domain from referer values before forwarding to the target server. If a request originates from https://proxyorb.com/some/path?__pot=..., the outbound Referer header is reconstructed as the original target URL (https://example.com/some/path) — the proxy domain is never leaked to upstream servers.
-- Pseudocode: normalize referer before forwarding upstream
function sanitizeReferer(referer):
if referer is a proxy URL:
return reconstruct_original_url(referer) -- e.g. "https://example.com/path"
if referer's origin equals proxy_origin:
return "" -- suppress: don't leak proxy domain to upstream
return referer
JavaScript Execution Context: Every JavaScript file served through the proxy is modified (URLs rewritten) and executed in the proxy's origin. A malicious script from evil.example.com proxied through ProxyOrb runs in the proxyorb.com origin and has full access to the local storage, cookies, and IndexedDB of that origin — which includes data from every other target site the user has accessed through the proxy.
The Malicious Proxy Threat Model
For educational purposes, it is worth being explicit about what a malicious proxy could do that ProxyOrb deliberately does not:
Credential Harvesting: A malicious proxy could log every request body (containing passwords and form data) as it passes through the gateway.
Session Hijacking: Because all target site cookies are stored under the proxy domain, a malicious proxy operator could access those cookies server-side via the gateway.
Content Injection: The proxy necessarily modifies page content (to inject the Service Worker and rewrite URLs). A malicious proxy could inject arbitrary JavaScript — keyloggers, crypto miners, ad fraud scripts — invisible to the user.
SSL Stripping: If the proxy downgrades HTTPS connections to HTTP for the gateway-to-user leg, all traffic is plaintext.
ProxyOrb operates over HTTPS end-to-end and does not log request bodies. The operator of any web proxy has these capabilities, which is why choosing a trustworthy proxy operator matters as much as choosing a trustworthy VPN provider.
Mixed Content
Modern browsers enforce mixed content blocking: an HTTPS page cannot load HTTP sub-resources. ProxyOrb handles this by enforcing HTTPS on all outbound connections from the gateway, even when the target URL uses HTTP. The CSP override includes upgrade-insecure-requests to instruct the browser to upgrade any HTTP sub-resource URLs to HTTPS before loading.
This is generally desirable, but it can break sites that deliberately serve resources over HTTP (legacy CDNs, localhost resources, etc.).
9. The Ongoing Arms Race: Conclusion
When we started building ProxyOrb, the primary compatibility challenges were CORS and X-Frame-Options. Since then, Chromium has shipped CORB, CORP, COEP, COOP, and is developing Document-Isolation-Policy. The direction of travel is clear: browsers are becoming more aggressive about enforcing cross-origin boundaries, and each new mechanism requires proxy infrastructure to adapt.
The most significant upcoming challenge is likely the full deployment of COEP across major web applications. Sites that use SharedArrayBuffer for performance (video editors, IDEs, collaboration tools) are increasingly setting COEP: require-corp. As ProxyOrb strips this header to maintain compatibility, users who need the high-performance features that COEP enables will find them degraded in a proxy context.
For security researchers, the proxy architecture reveals something important: the same-origin policy is not a firewall. It is a model of trust based on URL structure. Web proxies exploit the fact that the SOP makes no intrinsic distinction between "these two resources are legitimately same-origin" and "these two resources have been URL-rewritten to look same-origin." The entire browser security stack above the SOP — CORS, CORB, CORP, COEP, COOP — can be seen as an attempt to add defenses that are more robust than URL-based origin identity.
Understanding this is essential for anyone auditing proxy services, designing browser security policies, or evaluating the real-world security posture of applications that may be accessed through proxies.
Frequently Asked Questions
Does a web proxy bypass the same-origin policy?
Not exactly. A web proxy works by URL rewriting: it transforms all cross-origin URLs into same-origin URLs, making the SOP's cross-origin restrictions irrelevant rather than bypassing them. From the browser's perspective, all content appears to come from the proxy's own origin, so no cross-origin boundaries are crossed. This is architecturally different from a bypass — the SOP still enforces its rules; the proxy just engineers the content so those rules never trigger.
How does CORS affect web proxy servers?
CORS affects proxy servers at two levels. First, the proxy must intercept OPTIONS preflight requests and respond with permissive CORS headers, since the real target server's preflight response (referencing the target origin) would not satisfy the browser's CORS check for the proxy origin. Second, the proxy must strip CORS headers from target server responses and replace them with headers referencing the proxy origin. The Access-Control-Allow-Credentials: true setting, combined with credentials: 'include' in the Service Worker, means all cookies from the proxy's origin accompany every proxied request.
What is CORB and how does it impact proxy services?
Cross-Origin Read Blocking (CORB) is a Chromium defense that prevents certain sensitive cross-origin responses (HTML, JSON, XML) from entering the renderer process when loaded as cross-origin sub-resources. For correctly-configured web proxies, CORB is generally not triggered because the URL rewriting makes all requests same-origin. However, CORB can cause issues during the period before the Service Worker is fully registered, when some requests may escape URL rewriting and be sent as genuine cross-origin requests. CORB was introduced as a Spectre mitigation and is defined in the WHATWG Fetch specification.
Can web proxies access HTTP-only cookies?
No. HttpOnly cookies are set by the target server and cannot be read by JavaScript — including JavaScript running in a Service Worker. However, the gateway receives these cookies when forwarding requests on behalf of the user, since the browser sends them in request headers. The HttpOnly flag prevents client-side JavaScript theft but does not prevent the proxy server itself from seeing the cookie values in transit. This is analogous to how HttpOnly protects against XSS but not against server-side interception.
Is using a web proxy safe from a browser security perspective?
It depends on the threat model. From the browser's perspective, all content served through a web proxy runs in the proxy's origin, meaning a vulnerability in one proxied site's JavaScript could potentially access data from another proxied site's session (since they share the same origin's cookie jar and storage). The proxy's operator is also a trusted party with access to all traffic in transit. For accessing non-sensitive content in restricted environments, the risk is typically acceptable. For authenticated sessions with sensitive services (banking, healthcare, government), users should understand that the proxy operator has the technical capability to observe that traffic, and should use only proxy services with auditable no-log policies and strong operational security practices.
This article reflects ProxyOrb's architecture as of early 2026. Browser security mechanisms evolve rapidly; readers are encouraged to check the WHATWG Fetch Standard, the W3C Content Security Policy specification, and Chromium's security design documents for the most current information.
Top comments (0)