Most people use the JWT compact serialization, which cannot carry the unprotected header at all. If you're exchanging JWT compact tokens, the header is protected by the signature or the encryption.
What? You mean protected by the _MAC_? The header is never encrypted: the header is how you even figure out what to do with the rest of the message at all. That is why it definitionally can not be protected by it (that's the definition of the cryptographic doom pricnople!) and is how the bugs I am referencing are exploited to begin with. The only sense that a JWT header is "protected" is that the spec calls it that.
Have you ever exploited a JWT vuln? Which one? Because odds are there's a way it boils back down to the JWT header design choice being silly.
I mean there's an easier way to have this conversation: if the header is "protected", how did the alg=none bug ever work?
In a JWS the header is integrity-protected by the signature if the alg isn't none. This is prominently noted in the specs and alg=none artifacts are referred to as "unsecured JWS". In a JWE the protected header is integrity protected by the AEAD cipher, because all encs must be AEAD.
The alg=none substitution issues happened because of bad usage of mediocre libraries. Other algorithm substitution can arise for the same reason. The invalid curve attacks were the ones that the spec didn't call out as a security consideration.
I support the arguments that say algorithmic agility is a bad idea and a new protocol with algorithmic agility shouldn't have come out at a time when other protocols (like TLS) were finally starting to catch on to this fact. But the JWT cat is out of the bag, and won't go back in: it's widely deployed and people are using it thinking it's solving problems they actually have. Education is the proper remedy.
The PASETO effort attempts to provide better answers and better design to an audience familiar with JWT, but there's also been an uptick in the kind of advice that heavily condemns JWT without supplying some migration paths. That latter brand of advice is harmful.
Same points I made before: if more than one library has a flaw, it’s a design flaw and not a one-off implementation flaw, and if you’re trusting the header before you validate (which is necessary!), then it is not meaningfully protecting anything, which is why those bugs work.
And, finally: we’ve put together an extensive list of recommendations, repeatedly, both in general and in the articles on this thread.