Paragon Initiative Enterprises Blog

The latest information from the team that develops cryptographically secure PHP software.

Promoting Misuse-Resistance in PASETO Libraries

Last month, Thomas Ptacek wrote API Tokens: A Tedious Survey on the blog, which talks about all things API Token.

His post covered JWT, PASETO (our design), and a few other token formats. He went on to clarify, on Hacker News, that:

The one thing I'm not super comfortable about here is my PASETO take. My attitude going in was that PASETO has a lot of boosters and not a lot of critical takes. I can beat up on Macaroons because we're using them, and I'm going to follow up with a post about what our Macaroons like like. I'm not doing that with PASETO. So, like, I stand by it, but take it for what it's worth.

What was his take, exactly? Our succinct understanding of the criticisms laid out in the article are as follows:

  1. There are too many versions; the old ones should be deprecated.
  2. PASETO's specification spells out how to avoid algorithm confusion for implementors.
  3. Decide between symmetric and asymmetric; don't support both use-cases.
  4. NIST algorithm support and CFRG involvement are unnecessary and possibly counterproductive.

Out of these criticisms, the first two are actionable and warrant further inspection, while the latter are Thomas's opinion.

Too Many Acceptable PASETO Modes?

In short, we agree with Thomas Ptacek's criticism here. We feel that supporting more than two modes in parallel is an unnecessary risk. He might argue that supporting more than one is an unnecessary risk, but the marginal utility is more important for many users.

So to that end, on January 1, 2022, we intend to deprecate Versions 1 and 2 of PASETO. All PASETO libraries are strongly encouraged to migrate towards support for Version 3 and/or Version 4. Tracking tickets are here: Specification,, PHP.

In 2022, the only acceptable tuples of version and purpose in use will be v3.local, v3.public, v4.local, and v4.public. That will reduce the set of supported modes to the same magnitude as we launched with.

Preventing Algorithm Confusion in PASETO

One of the first criticism of PASETO came from Neil Madden on the CFRG Mailing List, who argued that the first PASETO RFC draft did not sufficiently mitigate the algorithm confusion vulnerability in JWT. It's worth noting that all known implementations, at the time of this discussion, were not susceptible any attack. However, the RFC draft text did not go far enough to prevent someone from making an implementation mistake.

To address this, we've implemented three different measures at different layers to protect PASETO libraries from living dangerously.

First, we explicitly spelled out asserting that the key being used is the same type that's being expected in every operation (Encrypt, Decrypt, Sign, Verify) for all PASETO versions (V1, V2, V3, V4). By making this the first step in the specification, it becomes less likely that anyone will overlook or omit it by accident.

Second, we also included a page in the Specification repository dedicated to "Algorithm Lucidity" (i.e., avoiding Algorithm Confusion), with different guidance for object-oriented and procedural programming languages. TL;DR - Use Type Safety if you can.

While both of these steps are useful in preventing mistakes from happening, documentation doesn't sufficiently mechanize their detection or prevention. The onus is still on the developer to understand with what was written, and then comply with it.

That is why we also included the third layer of misuse-resistance: Test vectors that are expected to fail.

How Do Negative Test Vectors Help Secure PASETO Implementations?

Consider the three negative test vectors for PASETO v4:

    "name": "4-F-1",
    "expect-fail": true,
    "public-key": "1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2",
    "secret-key": "b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2",
    "secret-key-pem": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILTL+0PfTOIQcn2VPkpxMwf6Gbt9n4UEFDjZ4RuUKjd0\n-----END PRIVATE KEY-----",
    "public-key-pem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAHrnbu7wEfAP9cGBOAHHwmH4Wsot1ciXBHwBBXQ4gsaI=\n-----END PUBLIC KEY-----",
    "token": "v4.local.vngXfCISbnKgiP6VWGuOSlYrFYU300fy9ijW33rznDYgxHNPwWluAY2Bgb0z54CUs6aYYkIJ-bOOOmJHPuX_34Agt_IPlNdGDpRdGNnBz2MpWJvB3cttheEc1uyCEYltj7wBQQYX.YXJiaXRyYXJ5LXN0cmluZy10aGF0LWlzbid0LWpzb24",
    "payload": null,
    "footer": "arbitrary-string-that-isn't-json",
    "implicit-assertion": "{\"test-vector\":\"4-F-1\"}"
}, {
    "name": "4-F-2",
    "expect-fail": true,
    "nonce": "df654812bac492663825520ba2f6e67cf5ca5bdc13d4e7507a98cc4c2fcc3ad8",
    "key": "707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f",
    "token": "v4.public.eyJpbnZhbGlkIjoidGhpcyBzaG91bGQgbmV2ZXIgZGVjb2RlIn22Sp4gjCaUw0c7EH84ZSm_jN_Qr41MrgLNu5LIBCzUr1pn3Z-Wukg9h3ceplWigpoHaTLcwxj0NsI1vjTh67YB.eyJraWQiOiJ6VmhNaVBCUDlmUmYyc25FY1Q3Z0ZUaW9lQTlDT2NOeTlEZmdMMVc2MGhhTiJ9",
    "payload": null,
    "footer": "{\"kid\":\"zVhMiPBP9fRf2snEcT7gFTioeA9COcNy9DfgL1W60haN\"}",
    "implicit-assertion": "{\"test-vector\":\"4-F-2\"}"
}, {
    "name": "4-F-3",
    "expect-fail": true,
    "nonce": "26f7553354482a1d91d4784627854b8da6b8042a7966523c2b404e8dbbe7f7f2",
    "key": "707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f",
    "token": "v3.local.23e_2PiqpQBPvRFKzB0zHhjmxK3sKo2grFZRRLM-U7L0a8uHxuF9RlVz3Ic6WmdUUWTxCaYycwWV1yM8gKbZB2JhygDMKvHQ7eBf8GtF0r3K0Q_gF1PXOxcOgztak1eD1dPe9rLVMSgR0nHJXeIGYVuVrVoLWQ.YXJiaXRyYXJ5LXN0cmluZy10aGF0LWlzbid0LWpzb24",
    "payload": null,
    "footer": "arbitrary-string-that-isn't-json",
    "implicit-assertion": "{\"test-vector\":\"4-F-3\"}"

The first failing test (4-F-1) tests a v4.local token against an asymmetric keypair. Any PASETO implementation that passes all of the test vectors necessarily prevents local tokens from being processed by an API that only deals with asymmetric keypairs.

The second failing test (4-F-2) tests a v4.public token against a symmetric key. Any PASETO implementation that passes all of the test vectors necessarily prevents public tokens from being processed by an API that only deals with symmetric keys.

The above test cases are sufficient to prevent algorithm confusion attacks in any library that runs the PASETO test vectors in CI/CD.

The third failing test (4-F-3) confirms that a simpler failure mode isn't possible: Attempting to decrypt a v3.local. token with a Version 4 key.

The sum of the specification text, Algorithm Lucidity guidance, and test vectors should guarantee that all PASETO libraries avoid this class of vulnerability entirely.

Our Commitment to Security

We designed PASETO to help systems that need a JWT-like token format avoid the implementation failures baked into JWT. Our response to any security expert's criticism of PASETO will be to consider ways to improve the security of our design for its implementors and their users. Anything less would be a disappointment for everyone involved.

We'd like to offer our thanks to Neil Madden and Thomas Ptacek for taking the time to study our designs and levy criticisms that will ultimately lead to a more secure and reliable cryptographic token format for the entire Internet to enjoy.

If you'd like to get involved, the PASETO specification is available on Github.

About the Author

P.I.E. Staff

Paragon Initiative Enterprises

Paragon Initiative Enterprises is a Florida-based company that provides software consulting, application development, code auditing, and security engineering services. We specialize in PHP Security and applied cryptography.

Need Technology Consultants?

Will tomorrow bring costly and embarrassing data breaches? Or will it bring growth, success, and peace of mind?

Our team of technology consultants have extensive knowledge and experience with application security and web/application development.

We specialize in cryptography and secure PHP development.

Let's Work Together Towards Success

Our Security Newsletters

Want the latest from Paragon Initiative Enterprises delivered straight to your inbox? We have two newsletters to choose from.

The first mails quarterly and often showcases our behind-the-scenes projects.

The other is unscheduled and gives you a direct feed into the findings of our open source security research initiatives.

Quarterly Newsletter   Security Announcements