6 ms·
Necessary qualifier: for browser-based user sessions. Plenty of good uses for JWTs for service-to-service communication. edit: I read some of the linked stuff
by solatic 4mo ago
Necessary qualifier: for browser-based user sessions.
Plenty of good uses for JWTs for service-to-service communication.
edit: I read some of the linked stuff, e.g. https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba... . Please, if JWTs are such a horrifically insecure standard, go ahead and publish your means for hacking AWS STS's AssumeRoleWithWebIdentity , or don't publish and just exploit it by launching cryptominers in every Fortune 500 production AWS account. Let me know when you inevitably succeed, because JWTs are so insecure, right? /sarcasm
- kyrra 4mo agoJWT used to be bad due to libraries with poor defaults. Downgrade attacks were fairly common a number of years ago. Since most of the common libraries across all languages have gotten more sane defaults, it actually is pretty secure nowadays.
- tptacek 4mo agoIf we stipulate that, we're still left wondering what the utility is of a standard that creates affordances for the insecure defaults, as opposed to just designing it right from the beginning.
- ForHackernews 4mo agoSpec writers and library authors are human? Who knew
- tptacek 4mo agoI don't understand what this is meant to communicate. The standard is either good or it isn't. "Good effort" is not an engineering assessment.
- ForHackernews 4mo agoYour objection is that they should be "designing it right from the beginning" but that applies to all realms of endeavour. The reason they didn't is human frailty. If everyone simply designed everything right from the beginning we would live in nirvana.
- tptacek 4mo agoYou've completely missed my point. I don't even accept the premise of the JWT standard. But the eventual migration to safer default settings, in a format that continues to expend implementation effort to support settings nobody should use, is in fact a practical engineering problem with the standard.
- ForHackernews 4mo agoAnd they've published updates[0] and libraries have hardened their defaults and removed support for insecure values (e.g. alg='none'). I'm not sure what more you want? I'd rather use a refined, battle-tested standard with lots of eyes on it than some new untested contender produced by a handful of upstarts ("look, we just designed it right from the beginning! This time it's perfect!") PASETO reeks of second-system syndrome. [0] https://www.rfc-editor.org/info/rfc8725/ https://www.rfc-editor.org/info/rfc8725/
- tptacek 4mo agoI don't recommend PASETO either.
- doc_ick 4mo agoWhat do you recommend then? What technology has been designed, completed, then used for years without any updates or problems?
- kasey_junk 4mo ago
- henryoman 4mo agoNot for long
- unscaled 4mo agoPASETO and TLS 1.3 were also written by humans. TLS libraries (which are several orders of magnitude more complicated than JWT libraries) are also written by humans. If you passionately care about security and misuse-resistance you CAN write a spec that will lead to fewer implementation issues.
- ForHackernews 4mo agoYou must be young if you're pointing to TLS libraries as an example of doing it right and not getting into trouble with insecure implementations and downgrade attacks. https://wiki.freebsd.org/LibreSSL https://wiki.freebsd.org/LibreSSL
- unscaled 4mo agoI wish I was young. Did I explicitly said TLS __1.3__ or did I not? A lot of effort was put into making TLS 1.3 a stronger, less agile and more misuse-resistant standard than its previous iterations. And that effort worked.
- jeswin 4mo ago> utility is of a standard that creates affordances for the insecure defaults You could make the same argument about Cookies. > as opposed to just designing it right from the beginning And generally, it's quite difficult to design it right from the beginning because one would often start with the wrong assumptions. Most standards evolve, and it should be acceptable.
- tptacek 4mo agoNo, that doesn't square up. It's like arguing "you could say the same thing about TCP, because it allows you to build JWTs, which are a bad protocol".
- jeswin 4mo agoNot the same. HttpOnly/Secure cookies were added much later and was not the default. They should have been inaccessible to JS by default from the beginning, and this policy has been a source of countless attacks.
- unscaled 4mo agoIf memory serves me right, cookies were designed by Netscape in 1994 before JavaScript was even a thing. They were released in an early beta of Netscape (0.9 something), while Javascript was only added in Netscape 2.0. SSL 2.0 was only added in Netscape 1.0. So the HttpOnly/Secure attributes were not relevant to the first cookie design, which wasn't even a standard. When the first cookie standard (RFC 2109) was released, the Secure attribute was added. You could argue they missed HttpOnly, but JavaScript itself was highly non-standard and underspecified mess during this period (and for a while later too). Almost nobody was thinking about XSS as far as I can tell, and that term was probably only coined at least 2 or 3 years later (by Microsoft researchers[1]). At 1997, the people who even considered XSS, probably only saw this as an HTML injection issue that can be fixed at the injection site and doesn't require any special protections against JavaScript code. If you really want to point a finger at issues in the early cookie design, then you could talk about domain matches. Not making the port part of the matched domain and not allowing an explicit way to trigger an exact domain match with a specified domain was a mistake. And the confusing leading dot rules (probably for optimizing a substring match without parsing the domain components) was also a mistake. But RFC 2109 was replaced with RFC 6265 and now RFC 6265bis (which is not released yet, but is mostly implemented by the big browsers). These RFCs fix most of the big issues we had with cookies, and do not shy away from breaking existing behavior: setting SameSite=Lax as the default and restricting SameSite=None to secure contexts broke A LOT of sites for improve security. The changes made in RFC 6265 to forbid multiple cookies in one header also broke many sites. An equivalent approach in the JWT spec would be a new RFC that does the following: 1. Forbids implementing Unsecured tokens and removes alg="none". 2. Removes RSA and ECDSA (or at least deprecate them) and make Ed25519 the "Recommended+" signature algorithm. If we allow RSA and ECDSA for compatibility, they must be explicitly enabled with feature flags or some other marker that signals their insecurity and security advisories on their potential vulnerabilities must be attached. 3. Removes the entirity of JWE as it is currently implemented (to be replaced with encryption else that is NOT orthogonal to authentication). 3. Requires that HMAC secrets are specified as binary base64url data. They SHOULD be generated by a CSPRNG or a derived using a safe derivation method (such as HKDF-SHA256 with safe key material) and MUST be at least as long as the "security size" for the algorithm (i.e. 32 bytes for HS256, 48 bytes for HS384 and 64 bytes for HS512). 4. Makes the "exp" claim mandatory to set, and mandatory to verify. 5. Add a section with strict implementation guidelines for libraries, e.g. `parse()` functions that skip verifying the token should have a clear name like `inspect_without_verification()` or `dangerously_parse_without_verifying()` and `verify()` function should always receive a key that is strictly typed to a specific algorithm. 6. Remove or restrict the usage of fields that allow the JWT sender to dictate the keys used for verifying it, like "jku" or "x5c". For instance, the standard can mandate that when implementing these fields, the verifier MUST NOT accept any JWKS URLs that do not match one of the explicitly allowed patterns or X.509 certificates that are not signed by an explicitly trusted CA. [1] https://www.youtube.com/watch?v=mKAWpFdVcPY https://www.youtube.com/watch?v=mKAWpFdVcPY
- unscaled 4mo agoJWT libraries had poor defaults because the spec was poorly designed. Of course JWT can be implemented securely. Even XMLDSig can be implemented securely. But if the spec is not designed with security and misuse-resistance as a tier 1 priority, you will get more issues. The fact that we didn't see the same sheer volume of issues with PASETO or macaroon libraries (admittedly, the later are far less numerous). I can find only one CVE for a PASETO library from 2020, and this is an issue that has nothing to do with the algorithm itself (JPaseto < 0.3.0 switched the order of two arguments in their hash function call, generating weaker hashes). The reason PASETO won't have the same issues as JWT is the design (especially with v3/v4). There is no alg=none, symmetric keys are fixed size (so no weak keys can be used) and algorithm confusion is prevented by an explicit implementation guide[1] that strongly mandates that keys for different algorithm version have different types, and verification functions MUST reject a key of the wrong type. Is JWT safe now? Maybe. A lot of issues have been fixed, but new issues keep coming all the time. We're not even halfway into this year and I can count at least the following serious 2026 CVEs: CVE-2026-28802, CVE-2026-29000, CVE-2026-1529, CVE-2026-22817/8, CVE-2026-34950, CVE-2026-23993, CVE-2026-32597, just to name a few. Most of them are the same classic alg=none, signature verification bypass and algorithm confusion issues. The issues is that new libraries are coming all the time and the vulnerability elimination process for existing libraries is just a random scattershot. If a security researcher has happened across a vulnerability in library X and reported it, it's solved. If nobody has found it yet: though luck. Unless you pick a library that has been officially audited for these issues, you don't really know if it's truly safe. If you use a PASETO library, it's probably not audited either, but the chance of it having these common types of issues (and other issues, like psychic signatures[2]) are close to nil. --- [1] https://github.com/paseto-standard/paseto-spec/blob/master/docs/02-Implementation-Guide/03-Algorithm-Lucidity.md https://github.com/paseto-standard/paseto-spec/blob/master/d... [2] https://www.securecodewarrior.com/article/psychic-signatures https://www.securecodewarrior.com/article/psychic-signatures
- RagingCactus 4mo ago> Necessary qualifier: for browser-based user sessions. > Plenty of good uses for JWTs for service-to-service communication. This is the sensible conclusion right there. I agree JWTs are the wrong tool for the use case of user sessions in the browser. To give some more arguments: All the signature and encryption stuff in JWTs is complex. While common JWT libraries have now mostly got their stuff together, this has not always been the case. There were plenty of libraries accepting the "none" algorithm [1] or allowing attackers to forge tokens by using a public key as a shared secret [2]. This is the direct result of the complexity criticized in the linked blog post. JWTs also cannot do some stuff you want for user sessions. You can't invalidate them without keeping a revocation list somewhere. But if you have to check an identifier for revocation on every request you could just use an opaque session ID and look that up on every request instead! Sure, you can use short-lived tokens and refresh them all the time, but why bother with that for a typical application that has to keep some state anyway? All that being said, I wholeheartedly agree that there are use cases in distributed systems and machine-to-machine communication where signed tokens can be useful. Just please don't confuse the two cases. [1] https://nvd.nist.gov/vuln/detail/cve-2022-23540 https://nvd.nist.gov/vuln/detail/cve-2022-23540 [2] https://nvd.nist.gov/vuln/detail/CVE-2024-54150 https://nvd.nist.gov/vuln/detail/CVE-2024-54150 (just a random example from googling, I don't know what library made this one infamous)
- nine_k 4mo ago> if you have to check an identifier for revocation on every request you could just use an opaque session ID and look that up on every request instead! One reason could be the size. A revocation list only needs to keep session IDs of recently logged-out sessions, for which the token's TTL hasn't yet expired. It may be a much smaller list than a list of every active session. Also, a JWT (or a Macaroon, etc) can store a large amount of details about the session in a cryptographically secure, unforgeable way. This rids you of the necessity to store all that in your active session database, again cutting the size.
- agwa 4mo agoAs someone who operates a PostgreSQL database containing 27 billion SSL certificates, each 1-2kb each, with a bunch of secondary indexes that get inserted in random order, I find it pretty incredible that people see the need to optimize their session database. At what scale does the size of the session database actually matter? Those stateless tokens may be "unforgeable", but they are replayable, and if you're not mindful of that you can have security vulnerabilities.
- jeltz 4mo agoI agree with your first part but your edit is a logic fallacy. I don't need to be able to hack something to say that it is insecure. For example: I don't know how to exploit SAML but I know it is a terrible standard dur to making all of the XML parser an attack surface. I am not a security researcher so I dont know how to find exploits in XML parsers but I know having a huge attack surface is bad.
- tptacek 4mo agoThere is in fact a long lineage of vulnerabilities caused by JWTs in real applications.
- unscaled 4mo agoA non-exhuastive list of CVEs from this year alone: CVE-2026-28802, CVE-2026-29000, CVE-2026-1529, CVE-2026-22817/8, CVE-2026-34950, CVE-2026-23993, CVE-2026-32597. Most of them are the same classic alg=none, signature verification bypass and algorithm confusion issues.
- jkrejcha 4mo agoJOSE can still have problems if it's secure when implemented properly. A lot of API surfaces for them can kinda suck. If secure when held right was equivalent to good, then that would apply also to stuff like X.509 There are better alternatives for a lot of cases, standard session tokens or API keys are a popular one in use in most major websites online and work pretty much perfectly for most use cases. I'm not gonna say those standards are completely without merit. The best thing about them is that it is some basic standard on passing stuff around that isn't like ASN.1 encoded or whatever, to which the tooling seems incredibly brittle and bug-prone.
- Rapzid 4mo agoYeah, hasn't it been "best practice" for a decade or more to treat JWT like a ticket and swap it for a cookie-based session ID in anything browser-like? Then you just do all the cookie session "best practices" to lock it down.
- jzelinskie 4mo agoLots of very bad uses for JWTs for service-to-service communication, too. There are often way more standard/foolproof alternatives than how lots of people use JWTs on the backend. I feel like discussions like these usually will surface PASETO/Macaroons/Thin Mints as the fix without acknowledging that the complexity of distributed token passing with arbitrary attenuation isn't a fit for most use cases. That all being said, sometimes JWT is the right solution for the job! It's the core skill of software engineering to be able to take in all the arguments and tradeoffs and make the right choice for your scenario. Full disclaimer: Take what I say with a grain of salt because I build a project (SpiceDB) that advocates for a more centralized approach for one of the backend JWT use cases: fine-grained authorization.
- dheera 4mo agoWhy is JWT so messy? base64(something) + "." + base64(something else)? Why not just base64(JSON.stringify(everything)) ?
- locknitpicker 4mo ago> Necessary qualifier: for browser-based user sessions. True. Still the article can't really make any case, other than pointing misuses and throwing a few baseless assertions. In fact, it surprised me to see such an article featuring so many upvotes. The primary use for JWTs is to allow resource owners to perform stateless JWT validation,and then be able to trust a JWT's payload to perform authentication and authorization. This doesn't mean what the blogger think it means. These processes become stateless because the resource owner does not need to perform any inline request to be able to tell whether the JWT can be accepted or not. Meaning: - The JWT is signed and/or encrypted, and the resource owner can use it's JSON Web Key set verify and/or decrypt it. - the JWT, once deemed valid, includes metadata that helps the resource server determine if the JWT should still be accepted. This includes timestamps of when it was issued at and when it expires, a JWT ID to check a revocation list, and even a few user claims such as user id, audiences, scope, etc. A resource owner does not need to perform any request inline to perform those checks. The revocation list needs to be kept fresh but it can be refreshed as a background task. At most, if the JWT is expected to be single-use, the resource owner is able to run the nonce/JWT ID through a denylist. - one of the primary values of JWTs is performance. For the vast majority of usecases, the whole verification&validation flow is stateless. This means no outbound request is needed to execute authentication and authorization checks. Instead of plowing through something between 20-100ms of latency to handle auth in each request, the whole flow takes less than 1ms. I don't think the blogger fully grasps this nuance. Outright asserting that JWTs introduce performance issues completely erodes any trust that the blogger has a solid grasp on the subject.
- swiftcoder 4mo ago> Please, if JWTs are such a horrifically insecure standard, go ahead and publish your means for hacking AWS STS's AssumeRoleWithWebIdentity The standard and AWS' specific implementation thereof are two different things. Can you afford a security org the size of Google or Amazon's security orgs? If not, you are playing a different ballgame.
- unscaled 4mo agoWow, Fortune 500 companies are using an insecure technology, get hacked and exploited by cryptominers and PII burglars and then just patch their vulnerabilities and call it a day? This never happened before! /sarcasm Just because a certain practice is popular, doesn't mean it's good for security, and it definitely does not mean the companies who do this never get hacked. Popular != Unhackable. I don't believe this needs to be stated. Cases in point: - Passwords limited to 8 characters - Passwords hashed with a fast, single-iterated hash (with or without salt, that's not the main point, we are not in 2003 anymore goddamnit, and GPUs are a thing!) - Passwords stored in cleartext - Using old-style C/C++ without bounds checking and fuzzing and treating stack overflow exploits as just a fact of life we'd have to live with, while most other languages don't get anymore (and if you have to use C/C++ for reasons there are ways to prevent this). - Injecting unverified user input directly into SQL strings. - Using ancient software without ever patching or updating vulnerable versions.