The 'None' Identity: How a Polite Variable Turned jose-swift into a Security Nightmare
Jan 11, 2026·6 min read
Executive Summary (TL;DR)
The jose-swift library for Swift has a classic 'None Algorithm' vulnerability. By setting the JWT header's 'alg' field to 'none', the library's verification function immediately returns `true` without checking any signature. This allows total identity forgery and privilege escalation without knowing any secret keys.
A critical authentication bypass in the jose-swift library allows attackers to forge JSON Web Tokens (JWTs) by simply telling the server verification isn't necessary. The library honors the 'none' algorithm in the header and explicitly skips signature verification.
The Hook: Trust Me, I'm an Admin
JSON Web Tokens (JWTs) are the duct tape of modern authentication. They hold the internet together, passing claims from client to server like digital VIP passes. The entire security model relies on one crucial assumption: the signature. Without it, a JWT is just a JSON blob that anyone can edit. If I change "user_id": 123 to "user_id": 1 (the admin), the signature should break, and the server should reject me.
But what if you could just politely ask the server not to check the signature? That is the premise of the 'None Algorithm' attack—a vulnerability so old it feels like archaeological digging, yet it keeps appearing in modern libraries.
Enter jose-swift, a comprehensive Swift implementation of the JOSE standards (JWS, JWE, JWK). It's used by iOS and server-side Swift developers to handle secure tokens. Unfortunately, until very recently, it suffered from a catastrophic logic flaw. It treated the JWT header not as a claim to be verified, but as a set of instructions to be blindly obeyed. If the token said, 'Don't worry about checking this,' the library effectively replied, 'Understood, have a nice day,' and let the attacker right through the front door.
The Flaw: A Polite Failure
To understand the gravity of this bug, we have to look at how JWT libraries usually handle verification. The process should be: receive the token, verify the signature using a trusted key (like a shared secret or a public key), and then trust the data.
The vulnerability in jose-swift is a textbook implementation of CWE-347: Improper Verification of Cryptographic Signature. The library's logic was dangerously helpful. It parsed the header first to determine which algorithm was used to sign the token. If the header specified "alg": "none", the verification function hit a specific check designed to shortcut the process.
Instead of throwing an error like InvalidAlgorithm or UnsecuredTokenNotAllowed, the library's verify function simply returned true. It validated the token because the token truthfully claimed it had no signature. Technically correct, perhaps, but security-suicide in practice. This means the verification function wasn't verifying the authenticity of the token; it was verifying whether the token complied with its own header. Since a 'none' token requires no signature to be valid according to the spec, the library considered it valid for authentication.
The Code: The Smoking Gun
Let's look at the crime scene. The vulnerability lived in Sources/JSONWebSignature/JWS+Verify.swift. As a security researcher, finding code like this produces a mix of excitement and horror.
Here is the vulnerable function logic:
public func verify<Key>(key: Key?) throws -> Bool {
// The fatal flaw:
guard SigningAlgorithm.none != protectedHeader.algorithm else {
return true // <--- The "Welcome Home" mat
}
// Actual verification logic for real algorithms (HS256, RS256) follows...
// ...
}Do you see it? The guard statement checks if the algorithm is none. If it is none (meaning the condition != fails), it drops into the else block (or rather, fails the guard depending on swift syntax nuance, but here the logic flow effectively shortcuts).
Wait, let's look closer at the logic provided in the report. The code explicitly checks: guard SigningAlgorithm.none != protectedHeader.algorithm. If the algorithm is none, the guard fails, and the code executes the else block (or implies a return path). In the provided context, the logic was simplified to: "If algorithm is none, return true."
This is a critical misunderstanding of the JWT RFC. While the RFC defines a 'none' algorithm for unsecured JWS, it is intended for debugging or very specific, non-security contexts. A library intended for verification should never accept none by default unless explicitly configured to allow unsecured tokens. In jose-swift, this behavior was the default. No flags, no config options—just an open door.
The Exploit: Becoming Admin
Exploiting this is trivially easy. We don't need to crack a private key, brute-force an HMAC secret, or perform a timing attack. We just need to craft a JSON file and Base64 encode it. Here is the recipe for disaster.
Step 1: The Header
We tell the server we are using the none algorithm.
{
"alg": "none",
"typ": "JWT"
}Step 2: The Payload
We give ourselves whatever permissions we want. Let's be the admin.
{
"sub": "admin_user",
"role": "superuser",
"iat": 1700000000
}Step 3: The Assembly
We Base64Url-encode the header and the payload. We leave the signature section empty, but we must include the trailing dot to maintain the header.payload. structure.
Header: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
Payload: eyJzdWIiOiJhZG1pbl91c2VyIiwicm9sZSI6InN1cGVydXNlciIsImlhdCI6MTcwMDAwMDAwMH0
Final Token:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbl91c2VyIiwicm9sZSI6InN1cGVydXNlciIsImlhdCI6MTcwMDAwMDAwMH0.
When we send this token to an application using the vulnerable jose-swift version, the app parses the header, sees none, and the verify function returns true. The application logic then proceeds to read the sub claim ('admin_user') and grants us full control.
The Impact: Why We Panic
This is a Critical (9.8) severity issue for a reason. Authentication bypasses don't get much cleaner than this. The impact includes:
- Identity Theft: An attacker can impersonate any user in the system just by guessing their user ID or email.
- Privilege Escalation: If the application uses JWT claims for authorization (e.g.,
"isAdmin": true), the attacker gains immediate administrative access. - Data Exfiltration: With admin access, the attacker can likely query private data, export user bases, or modify critical system configurations.
- Zero Prerequisites: The attacker does not need to be an authenticated user to start with. They just need to know the endpoint expects a JWT.
This vulnerability renders the entire cryptographic protection of the JWT implementation null and void. It is the security equivalent of a bank vault that opens if you whisper 'please'.
The Fix: Closing the Loophole
The remediation is straightforward: Upgrade. The maintainers have patched the issue in the latest release (versions 0.5.1 and above). The fix likely involves removing the shortcut return or explicitly throwing an error when none is encountered during verification.
Developer Takeaway
If you are writing or maintaining a JWT library, or even manually validating tokens:
- Never trust the header: The
algheader is user input. It is untrusted until validated against an allow-list. - Enforce Algorithms: When calling a verify function, explicitly pass the algorithm you expect (e.g.,
verify(token, key, algorithm: .HS256)). If the token header doesn't match the expected algorithm, fail immediately. - Ban 'None': Unless you are writing a debugger, the
nonealgorithm should be treated as a malicious payload by default.
If you cannot update immediately, you must implement a manual check before passing the token to the library:
// Temporary Mitigation
let header = try JWS.decodeHeader(token)
if header.algorithm == .none {
throw AuthError.invalidAlgorithm
}
// Proceed to verifyOfficial Patches
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
jose-swift beatt83 | < 0.5.1 | 0.5.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-347 |
| Attack Vector | Network (API) |
| CVSS | 9.8 (Critical) |
| Impact | Auth Bypass / Privilege Escalation |
| Exploit Status | Trivial / High Likelihood |
| Complexity | Low |
MITRE ATT&CK Mapping
The software does not correctly verify the cryptographic signature for data, allowing the data to be modified or forged.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.