Remove inherited header applied by splat path in _headers

Is there a way to remove a header that’s previously been set in _headers? I can override a header e.g. with this:

/*
  X-Frame-Options: DENY
/some/path
  X-Frame-Options: SAMEORIGIN

But I don’t know how to unset the header (there’s no value to this header that means “default please”).

Setting it to nothing (i.e. the following block) didn’t seem to work, it then gets the inherited DENY (in fact the Netlify build states that it’s an invalid header rule):

/*
  X-Frame-Options: DENY
/some/path
  X-Frame-Options:

Right now I’m just setting to a value that doesn’t have any meaning (ALLOW seemed the most appropriate), but I don’t love doing that as it’s still actually setting this header, which then gives an error in the Chrome console (not sure about other browsers right now) which isn’t exactly great.

Is there a way to unset a header that I don’t know of?

1 Like

Flip the rules around – more specific rules should be higher in the file because it’s read from top-to-bottom :smiley:

As in specify the /some/path URL with no headers so the /* one doesn’t add the other header?

FWIW I originally tried to convert DENY to SAMEORIGIN for the /some/path URL (but it turns out the origin is different so I really do need it completely unset), and when I did so I originally put the /some/path rule at the top and it had no effect. That’s the reason the /some/path URL is at the bottom in my top example.

But yeah, if you’re saying that after matching any rule it stops processing the rest of the file then yes, having it at the top with (I guess?) no header rules defined at all should have the desired effect. But I have to say that in my very limited experience of something slightly different, this isn’t how it works. Con you confirm?

(In related news, I have to say that the headers playground has been quite nice for helping me ensure the rules I add in are correct, but it’d be soooooo good if, after entering the rules and clicking the “Test rules” button you could then enter a path and it’d tell you what headers it’d get. All it does currently is tells you if the syntax is any good, and tells you what the equivalent netlify.toml versions of the rules would look like.)

Change this to:

/some/path
  X-Frame-Options: WHATEVER-THE-DEFAULT-IS
/*
  X-Frame-Options: DENY

With this, when analysing the rules, your /some/path route will find the specific rule that it needs before the /* rule is found :slight_smile:

Okay thanks for confirming (though as I say, my testing suggested literally the opposite of this - the more specific rule had to go after in order to actually override).

However, overriding with a fixed value is not my issue - my real issue is that, as far as I am aware, there is no default for this header. The default is an unset header, meaning “allow in all situations”. This is my main problem - I can’t find out how to unset the already-set header in Netlify.

I have a theory though I’ve not put it to the test –

/some/path
  [leave this blank, or populate with other applicable rule(s)]
/*
  X-Frame-Options: DENY

Strictly speaking, the /some/path route will ‘match’ with the blank ruleset and shouldn’t populate X-Frame-Options!

Just tested this and it doesn’t work I’m afraid.

To better demonstrate my point, I have made four sites:

  • https://alexr-headers-specific-first-value.netlify.app/ where the path to “override” is first in the _headers file as you suggest, but set to a specific value ALLOW which is invalid but would “work” if the override took effect, but the override doesn’t take effect
  • https://alexr-headers-specific-first-blank.netlify.app/ where the path to “override” is first in the _headers file as you suggest, and blank as you suggest - this doesn’t work
  • https://alexr-headers-specific-last-blank.netlify.app/ where the path to “override” is last in the _headers file as my experimentation has suggested needs to be the case, but blank as you suggest - this doesn’t work
  • https://alexr-headers-specific-last-value.netlify.app/ where the path to “override” is last in the _headers file as my experimentation has suggested needs to be the case, and set to a specific value ALLOW which, as above, is invalid but does work, and because the override takes effect this correctly sets the header to the invalid value so the page can be iframed. But there’s a console error as the header is not valid.

So I think you have it the wrong way round - the more specific path does have to go after the splat path in order to override, but I can’t find a way to unset a set header, only set it to a new value, which is no good to me here.

1 Like

I need this too, remove default X-Frame-Option

@Pie do you have any more from Netlify support on this after my last message?

Hey! Yeah – re-writing a header isn’t going to happen, I’m afraid. The way our logic works is that we’ll parse the first matching rule, hence why the catch-all rules need to be lower. Although there’s no regex to hand, I’m sure there’s a way of making it work!

Rather than looking to overwrite headers, we should look to get them right first time.

Yeah – re-writing a header isn’t going to happen, I’m afraid.

I’ve already said that rewriting works just fine, as long as you specify the overrides further down the file (literally the opposite of what you’re saying). (I don’t suppose you had a look at the examples I gave?)

Rather than looking to overwrite headers, we should look to get them right first time.

I understand what you’re saying, but I’m not trying to overwrite a header set by mistake or anything (though I actually can do this if I want to!) but remove entirely an already-set one (i.e. unset a given header), because the header in question must be absent for a given mode, but will have been set for all other paths by the catchall, and it’s impractical to say the least to specify “every path except X should get header Y” in the headers file without using a catchall and a single “unset” path, no? (If it’s not please tell me how to - does it accept bang syntax?)


With the utmost of respect I feel like you’re not reading what I’m saying. I keep saying that experimentally I have found the exact opposite of the advice you’re giving regarding rule order and I have given actual real examples as Netlify-hosted sites and you are still adamant that’s not the case. I also feel that rather than looking into my issue, you seem to have it in your head that something works a particular way (which appears to be incorrect) and that’s that (“why does this guy keep on going on about this thing I already said works like this?”). And regardless of all of that, you’re focussing on the wrong thing - order of rules to override a header, rather than my question of “is it possible to unset a header rather than override it?” - I already know how to override and am using it as temporary hacky solution to my issue.

So with that in mind, I feel that somehow our communication isn’t working out. Maybe you’d like to hand this “case” over to another support operative as you and I seem to be going in circles at the moment?

Hi @alexrussell,

Just wanted to clarify that unsettling a default header like x-frame-options and is unlikely that we will change this.

To summarize:
No, there is no way to unset a default header.
Yes, overwriting the default value works, but that doesn’t solve your concern as x-frame-options does not have an allow-all directive.

If you do need to embed your Netlify site in a frame, you’ll need to be explicit in which domains are allowed.

Hope that helps.

Cheers Dennis. Just to confirm, when you say “unsetting a default header” you mean a header I have manually set using a catchall rule, right, not a default header as set by Netlify’s own CDN. (Because that’s what I’m talking about here - unsetting a header I have set myself, not trying to undo any Netlify-default stuff.)

As for your suggestion of “you’ll need to be explicit in which domains are allowed” - how do you propose I do this? I know the x-frame-options header used to have an “allow from” directive but that was never standard, only patchily implemented and is now advised against. Is there another way I’m not seeing? Because yes, explicitly allowing a given origin could possibly work for me.

Also need this feature if you figure it out @alexrussell - I’ve explored everything you did prior to arriving here.

Hey Alex and Isaac,
Can you please share a request where you’re seeing that Netlify sets the X-Frame-Options header? I set up a less good demo of your site here: https://pedantic-noether-8175c8.netlify.app/ and removed the _headers file, and am seeing the page in the frame with no console errors.

Hi Jen, I feel that what I’m saying is being misunderstood. This is not Netlify setting the x-frame-options header by any kind of default. This is me personally setting it on a splat path, and thus it’s being inherited by “sub” paths, one of which I want to remove it for. See my initial post here for examples of how I’m trying to achieve this.


So I’ll rephrase the question:

Is there a way I can instruct Netlify to always set a given header (in my case x-frame-options, but this could be any header) for all paths except a given “exclude list” of paths (in my case a single path).

I would like to always send X-Frame-Options: DENY for all paths except for path /specific/path/here. For that path, I need the header to not be present. (I can’t set it to another value, it has to not be sent at all.)

Is this a better request?

Hey @alexrussell,
Thanks for further clarifying. What you’re hoping to do is unfortunately not possible today, but we do have an open feature for this internally and I’ll add this thread to the mix so we can be sure to notify you if/when this update ships.

2 Likes

Cheers for clarifying @jen

1 Like

Hi @jen & Support Team,

I’m also facing similar type of the problem with Netlify headers. I’m using Google Optimize tool for the A/B testing and while accessing the site in this tool, site is showing below error message.

Refused to display 'https://tbo.clothing/' in a frame because it set 'X-Frame-Options' to 'deny'

After investigating, I found that Google (https://optimize.google.com) is trying to access our site inside their iframe.

I have tried all the ways to set Netlify headers, so Google can access our page, but every time getting the same error.

Below is the list of configuration that I have used. Could you please help me to resolve this issue.
Thanks!

{
    resolve: `gatsby-plugin-netlify`,
    options: {
        headers: {
            '/*': [
               `Content-Security-Policy: frame-ancestors https://optimize.google.com`,

               // `X-XSS-Protection: 1; mode=block`,
               // `X-Content-Type-Options: nosniff`,
               // `Referrer-Policy: same-origin`,
               // `Access-Control-Allow-Origin: *`,
               // `X-Frame-Options: SAMEORIGIN`,
               // `Content-Security-Policy: frame-ancestors 'self' https://optimize.google.com`,
               // `X-Frame-Options: ALLOW`,
               // `X-XSS-Protection: 0`,
               // `Access-Control-Allow-Origin: *`,
            ],
            '/*.js': ['Cache-Control: public, max-age=31536000, immutable'],
            '/*.css': ['Cache-Control: public, max-age=31536000, immutable'],
            '/fonts/*': ['Cache-Control: public, max-age=31536000, immutable'],
        }
    }
}

Hey there, @allan.perrottet :wave:

Looks like this thread has been a bit quiet since you first reached out. Are you still encountering this issue with headers?

If you are, can you please respond with:

  1. Your Netlify site ID and/or site URL
  2. Your build log
  3. Any additional troubleshooting you have done in the past 7 days