Your CDN cache hit ratio takes a nosedive the second your origin server attaches a Set-Cookie header to images, CSS files, or JavaScript bundles. StackPath, like almost every caching proxy out there, assumes any response bearing a cookie contains private user data. The default behavior is simple: bypass the cache entirely.
Here’s how to write a StackPath EdgeRule that catches static file extensions, drops that incoming Set-Cookie response header right at the PoP, and forces the edge to cache those assets globally.

Why Origin Servers Slap Cookies on Static Files
Static assets should be completely stateless. A browser asking for main.css or a SVG icon has no business receiving a session identifier. Yet, production servers leak cookies onto static files all the time.
I run into this regularly across three setups:
- Eager WordPress plugins: Poorly built plugins hook into
plugins_loadedorinitand callsetcookie()on every single request, including 404 fallbacks or rewrite endpoints serving WebP images. - PHP session auto-start: If someone left
session.auto_start = 1on inphp.ini, any file request hitting PHP hands out aPHPSESSIDcookie automatically. - Node.js and Express backends: Placing middleware like
express-sessionabove yourexpress.static()mount causes Express to issue session cookies for every single stylesheet and script.
When StackPath grabs an asset from your origin and spots that Set-Cookie header, strict RFC rules kick in. Storing that response could accidentally leak one user’s session token to everyone else on the internet. To stay safe, StackPath hands the asset back with a cache status of MISS or BYPASS.
Your edge server turns into an expensive, dumb reverse proxy. Every request hits your origin, and an asset that should load from edge memory in 15ms ends up taking 350ms across a full origin TLS handshake.
Inspect the Problem with cURL
Before modifying edge rules, check whether your static files are actually leaking cookies. Fire a quick curl -I against one of your static assets through your CDN hostname:
curl -I https://cdn.example.com/wp-content/themes/custom/assets/app.min.jsCheck the headers coming back. If your origin is acting up, you’ll see something like this:
HTTP/2 200
date: Thu, 20 Feb 2025 14:10:22 GMT
content-type: application/javascript; charset=utf-8
set-cookie: PHPSESSID=d8a7fbc29e0114a7; path=/; HttpOnly
set-cookie: user_tracker=anon_893; expires=Fri, 20 Feb 2026 14:10:22 GMT; path=/
cache-control: public, max-age=604800
x-hw: 1740060622.dop014.fr1.t, 1740060622.cds028.fr1.c
x-cache: MISSLook at x-cache: MISS. Even though cache-control says the file can be cached for a week, that set-cookie line overrides everything. Run that exact command again a minute later and you’ll still get a MISS. StackPath refuses to hold onto it.
Step 1: Open StackPath EdgeRules
You can fix this at the CDN level without waiting on an origin deployment by using StackPath EdgeRules. These rules intercept the request and response lifecycle directly at the edge PoP.
- Log in to the StackPath Control Portal.
- Head to Sites and pick the delivery site you want to fix.
- In the sidebar, click EdgeRules.
- Click the Add EdgeRule button.
StackPath runs rules sequentially from top to bottom. If you already have rules set up to bypass CDN edge cache for logged-in WordPress users or to ignore tracking query strings, make sure you slot this rule in the right order so they don’t step on each other.
Step 2: Match Static Asset Extensions
We need a targeted condition that grabs only static files. You definitely don’t want to strip cookies off login forms, checkout pages, or dynamic API endpoints.
Set up the rule criteria like this:
- Rule Name: Strip Set-Cookie on Static Assets
- If: Request URL Path Extension
- Operator: Matches Regex (or In List, depending on your portal layout)
Add the standard static file extensions for your assets:
(css|js|jpg|jpeg|png|gif|webp|avif|svg|ico|woff|woff2|ttf|eot|mp4|webm)If your portal version provides the File Extension condition with a comma-separated list, drop them in directly:
css, js, jpg, jpeg, png, gif, webp, avif, svg, ico, woff, woff2, ttf, eot, mp4, webpLeave extensions like php, html, and json out of this list. Those payloads almost always need session cookies intact.
Step 3: Strip the Set-Cookie Header and Force Cache
Now configure what happens when an asset matches that extension list. We have two jobs: purge the offending header and explicitly tell the edge to cache the clean response.
Under the Then section, add these actions:
- Action 1: Modify Response Header
- Type: Delete / Remove Header
- Header Name:
Set-Cookie
- Action 2: Edge Cache TTL
- Behavior: Override Origin
- TTL: 31536000 seconds (1 year, or whatever TTL suits your versioning strategy)
- Action 3: Browser Cache TTL
- Behavior: Override Origin
- TTL: 604800 seconds (7 days)
StackPath drops the Set-Cookie header before the response enters the edge storage layer. Because the response is stripped clean during evaluation, StackPath treats it as cacheable public content and writes it straight to disk.
Hit Save EdgeRule. It usually takes between 30 and 60 seconds for the rule to propagate across all edge PoPs.
Handling Origin Cache-Control Gotchas
Sometimes stripping Set-Cookie still leaves you with a MISS. If your origin framework dumped a cookie on an image, chances are it also passed along something like Cache-Control: private, no-cache, no-store. If that header reaches StackPath, the edge will respect the no-store directive even without the cookie present.
To work around this, add another action to that same EdgeRule:
- Action: Add / Modify Response Header
- Action Type: Overwrite / Set Header
- Header Name:
Cache-Control - Header Value:
public, max-age=31536000, immutable
If you’re using fingerprinting or hashes in your asset filenames, check out our guide on configuring Nginx cache-control immutable headers to see why the immutable flag helps keep repeat client requests at zero. Forcing this header at the edge prevents rogue origin headers from sabotaging browser caches.
Fixing the Root Problem at the Origin
Edge rules give you an instant band-aid, but leaving the origin alone wastes resources. Generating and sending millions of useless cookie headers eats up origin CPU cycles and bandwidth.
Origin Fix for Nginx
If you run Nginx at origin, make sure static locations don’t pass cookie headers back to the proxy. Open your virtual host file (usually in /etc/nginx/sites-available/):
location ~* .(css|js|jpg|jpeg|png|gif|webp|avif|ico|svg|woff2)$ { fastcgi_hide_header Set-Cookie; proxy_hide_header Set-Cookie; expires 365d; add_header Cache-Control "public, no-transform, immutable"; access_log off; log_not_found off;
}Validate the config and reload:
sudo nginx -t && sudo systemctl reload nginxOrigin Fix for Apache / .htaccess
On Apache origins, use mod_headers to strip the header in your virtual host or root .htaccess:
Header unset Set-Cookie Header set Cache-Control "max-age=31536000, public, immutable"
Stopping the cookie at the source means StackPath caches cleanly out of the box without relying solely on edge header rewrites.
Verify the Edge Fix with cURL
With the EdgeRule live and the origin sorted, verify everything using curl. We need to confirm two things: the Set-Cookie header is completely gone, and the cache header flips to HIT.
Make the first request to warm the edge:
curl -I https://cdn.example.com/wp-content/themes/custom/assets/app.min.jsRun the exact same command immediately after:
curl -I https://cdn.example.com/wp-content/themes/custom/assets/app.min.jsYour response headers should look like this:
HTTP/2 200
date: Thu, 20 Feb 2025 14:15:48 GMT
content-type: application/javascript; charset=utf-8
cache-control: public, max-age=31536000, immutable
x-hw: 1740060948.dop014.fr1.t, 1740060948.cds011.fr1.h
x-cache: HITTwo key things changed:
set-cookieis completely gone from the response.x-cache: HITconfirms StackPath served the file straight from PoP memory without touching your origin.
If you serve webfonts across different domains, be careful when stripping headers. Take a look at our guide on fixing CORS font loading errors on CDNs so your edge rules don’t accidentally knock out required access-control headers.
Frequently Asked Questions
Will stripping Set-Cookie break dynamic WordPress cookies?
No, provided your EdgeRule only matches static file extensions (like .css, .js, and .png). WordPress handles authentication cookies and shopping carts on dynamic HTML pages and REST API routes. Those paths don’t match static asset extensions, so their cookies remain untouched.
Why didn’t StackPath automatically strip cookies for static assets?
Under the RFC 9111 HTTP Caching specification, caching proxies must not cache responses with a Set-Cookie header unless specifically told to do so. A CDN can’t safely guess whether a file contains personalized user data or not, so it takes the safe road and bypasses the cache.
What happens if a static asset URL has a query string?
StackPath evaluates the URL Path Extension independent of query strings. A request to styles.css?v=2.1.0 evaluates against the path styles.css, matches the css condition, and strips the cookie as expected.
Can I strip cookies from specific directories instead of extensions?
Yes. If your static files live under paths like /static/ or /dist/, you can change the condition to Request URL Path with the operator Begins With set to /dist/. Any file served from that directory will get stripped.
Next Steps for Your CDN Setup
Now that your static files are actually staying in edge cache, take a look at your dynamic URLs. Marketing tags and tracking parameters frequently bypass CDN caches by creating unique URL variants.
Take a look at our walkthrough on configuring CDN edge cache rules to ignore tracking query strings so UTM parameters don’t crush your origin cache hit ratio.

