Skip to content

Require exp when verifying webhook JWTs - #170

Merged
biglittlebigben merged 2 commits into
livekit:mainfrom
SashaMIT:fix/webhook-require-exp
Aug 20, 2026
Merged

Require exp when verifying webhook JWTs#170
biglittlebigben merged 2 commits into
livekit:mainfrom
SashaMIT:fix/webhook-require-exp

Conversation

@SashaMIT

Copy link
Copy Markdown
Contributor

Problem

WebhookReceiver.receive verifies the webhook JWT with JWT.require(alg).withIssuer(apiKey) only. java-jwt 4.x treats a missing exp as valid (claimVal == null passes the expiry check) unless withClaimPresence("exp") is set, so a hand-rolled token with a valid HMAC and no expiry verifies forever.

First-party AccessToken.toJwt always sets exp. This is the same gap livekit/protocol#1706 closed on the Go verifier, livekit/python-sdks#779 on Python, livekit/node-sdks#710 on Node, and livekit/server-sdk-ruby#97 on Ruby. This repo has no TokenVerifier; WebhookReceiver is the verify path.

Fix

Require the exp claim on verify.

Threat-model: the attacker can mint or obtain an HS256 token that omits exp. They do not control the verifier secret or clock. Signature verification still succeeds and the credential never ages out. That is permanent access from a forgotten expiry, not host or agent authority.

Test plan

  • ./gradlew test --tests io.livekit.server.AccessTokenTest --tests io.livekit.server.WebhookReceiverTest (5/5)
  • New case: signed token with no exp raises MissingClaimException
  • Revert-test: drop withClaimPresence("exp") and that case fails (token is accepted)
  • CI also runs WebhookReceiverTest so the new case is not AccessToken-only

Made with Cursor

java-jwt accepts a signed token with no exp unless presence is required.
WebhookReceiver is the Kotlin verify path.
@SashaMIT
SashaMIT requested a review from a team as a code owner August 19, 2026 07:15
@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1b17fad

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
server-sdk-kotlin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@erikhortsch erikhortsch left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment thread src/main/kotlin/io/livekit/server/WebhookReceiver.kt Outdated
@SashaMIT

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Pushed the RegisteredClaims.EXPIRES_AT swap.

@biglittlebigben
biglittlebigben merged commit e0d144c into livekit:main Aug 20, 2026
3 checks passed
@davidliu davidliu mentioned this pull request Aug 20, 2026
SashaMIT added a commit to SashaMIT/oss-contributions that referenced this pull request Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants