-
-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Crash when verifying a corrupt token #213
Comments
UpdateUpon further investigation, I think this is actually a crash that happens in Swift's implementation of For example, the following token header has been tampered with:
Base-64 decoding that as
I think that A workaround I've found was to include a check before attempting to verify the token. In that check I validate that the token is formed of three parts and that the header and payload parts can both be decoded as UTF-8 strings by verifying that |
This definitely looks like a Foundation issue under the hood and should not be crashing. It's caused by the print, it works if you remove it. I'm guessing you're seeing the issue when trying to return a token to the client or similar? |
Actually it is the verify fails, but at least for me it's not failing all the time |
Yes, the example above will not crash 100% of the time. From what I could gather, it will only crash (in Foundation, like you've mentioned) if there's a corruption to the token in a part that ends up becoming one of the keys in the JSON string. The way I found it was by accident while testing a server that I wrote. I wanted to check its resiliency against invalid tokens and was surprised by the crash. It definitely looks like a bug in Swift/Foundation and not JWTKit, but I think it might be worth trying to implement some sort of workaround since this basically provides a way for someone to DoS a server by sending bad tokens. Here's a smaller example with a hardcoded token that crashes every time: import Foundation
import JWTKit
struct TestPayload: JWTPayload {
var sub: SubjectClaim
var exp: ExpirationClaim
var flag: Bool
func verify(using algorithm: some JWTAlgorithm) async throws {
try exp.verifyNotExpired()
}
}
@main
struct JWTKitBugTest {
static func main() async throws {
do {
let keys = JWTKeyCollection()
await keys.add(hmac: "crashme", digestAlgorithm: .sha256)
let corruptToken = "eyJhbGciOiJIUzI1NiIsInR5xCI6IkpXVCJ9.eyJleHAiOjE3MzExMDkyNzkuNDIwMDM3LCJmbGFnIjp0cnVlLCJzdWIiOiJoZWxsbyJ9.iFOMv8ms0ONccGisQlzEYVe90goc3TwVD_QyztGwdCE"
_ = try await keys.verify(corruptToken, as: TestPayload.self, iteratingKeys: true)
} catch {
print(error)
}
}
} |
You're right that this does crash every time, however at this point I'm not sure what is really triggering the crash. This
is supposedly an invalid token too in that it's not UTF-8 and the header parses as |
Describe the issue
Attempting to verify a corrupt token results in the process crashing.
Vapor version
(unrelated to Vapor)
Operating system and version
macOS 14.7.1
Swift version
Swift Package Manager - Swift 6.0.3-dev
Steps to reproduce
verify
the corrupt token usingverify(token)
Below is a simple cli implementation that reproduces the issue:
Outcome
The process will crash with the fatal error below, even if the caller did not use
try!
and was calling within ado/catch
block:Thread 2: Fatal error: 'try!' expression unexpectedly raised an error: Foundation.JSONError.cannotConvertInputStringDataToUTF8(location: Foundation.JSONError.SourceLocation(line: 1, column: 17, index: 16))
Additional notes
The crash will not occur every time with the example above, but can be reliably reproduced by repeating the same crashing token after you've found one that does crash.
The text was updated successfully, but these errors were encountered: