🛡️ CVE-2026-50285 — pomerium

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-1284 OSV
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Pomerium Pre-Auth Memory Exhaustion via Unbounded zstd Decompression in HPKE Callback

Summary

The HPKE V2 URL decode path in pkg/hpke/url.go decompresses attacker-controlled zstd data without any size limit. On Pomerium deployments using the stateless authentication flow (Pomerium Zero / hosted authenticate), the proxy's /.pomerium/callback endpoint is reachable without credentials and processes attacker-crafted HPKE-encrypted payloads before the sender's identity is validated. Because Pomerium's HPKE receiver public key is publicly served, an attacker can encrypt a decompression bomb, deliver it to the callback endpoint, and cause unbounded memory allocation — crashing or degrading the proxy process.

Severity

High (CVSS 3.1: 7.5)

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

  • Attack Vector: Network — the /.pomerium/callback route on the proxy service is externally reachable.
  • Attack Complexity: Low — the receiver public key is publicly available at /.well-known/pomerium/hpke-public-key; no special conditions apply.
  • Privileges Required: None — the callback endpoint is intentionally pre-authentication (it is the OAuth landing page).
  • User Interaction: None
  • Scope: Unchanged — the DoS is confined to the Pomerium proxy process itself.
  • Confidentiality Impact: None
  • Integrity Impact: None
  • Availability Impact: High — repeated attacks can exhaust process memory and crash the proxy.

Affected Component

  • pkg/hpke/url.godecodeQueryStringV2 (line 171)
  • internal/authenticateflow/stateless.goCallback (line 385–393)
  • proxy/handlers.goCallback (line 105–107), route registered at line 53–54

CWE

  • CWE-400: Uncontrolled Resource Consumption
  • CWE-1284: Improper Validation of Specified Quantity in Input

Description

Unbounded zstd Decompression in decodeQueryStringV2

pkg/hpke/url.go defines two decoders. The V1 path is plaintext. The V2 path zstd-compresses the query string before encryption. Decoding reverses this with no output size cap (url.go:166–176):

```go

var zstdDecoder, _ = zstd.NewReader(nil,

zstd.WithDecoderLowmem(true),

)

func decodeQueryStringV2(raw []byte) (url.Values, error) {

bs, err := zstdDecoder.DecodeAll(raw, nil) // no size limit

if err != nil {

return nil, err

}

return url.ParseQuery(string(bs))

}

```

WithDecoderLowmem(true) reduces the decoder's own memory footprint but applies no cap on the output. A 19 KB input can produce 128 MiB of output; a 38 KB input can produce 256 MiB.

By contrast, the codebase applies LimitReader when decompressing in internal/zero/api/download.go:75:

```go

r = io.LimitReader(zr, maxUncompressedBlobSize) // 1 GB cap

```

The protection is available but not applied to decodeQueryStringV2, confirming this is an inconsistent defense.

HPKE Does Not Block the Attack — Sender Validation Is Too Late

DecryptURLValues for the V2 format (url.go:107–126):

```go

case IsEncryptedURLV2(encrypted):

senderPublicKey, err = PublicKeyFromString(encrypted.Get(paramSenderPublicKeyV2)) // attacker-controlled

// ...

sealed, err := decode(encrypted.Get(paramQueryV2))

// ...

message, err := Open(receiverPrivateKey, senderPublicKey, sealed) // HPKE decrypt — succeeds

// ...

decrypted, err = decodeQueryStringV2(message) // zstd decompress — UNBOUNDED

```

Open uses SetupAuth (HPKE authenticated mode). It only verifies that sealed was created with a key pair whose public half is senderPublicKey. Because the attacker supplies both k (sender public key) and q (sealed payload), they choose a consistent key pair themselves. The Open call succeeds with their own freshly-generated keys.

Sender identity is validated after DecryptURLValues returns (stateless.go:391–397):

```go

senderPublicKey, values, err := hpke.DecryptURLValues(s.hpkePrivateKey, r.Form)

// ... zstd already completed ...

err = s.validateSenderPublicKey(r.Context(), senderPublicKey) // now rejects attacker

```

The decompression memory spike occurs unconditionally before rejection.

Pre-Auth Execution Chain on the Proxy Callback

The proxy registers the callback route without any session or signature middleware (proxy/handlers.go:53–54):

```go

c := r.PathPrefix(endpoints.PathPomeriumCallback).Subrouter()

c.Path("/").Handler(httputil.HandlerFunc(p.Callback)).Methods(http.MethodGet)

```

For Stateless-flow deployments, p.Callbackauthenticateflow.Stateless.Callbackhpke.DecryptURLValues (unbounded decompress) → validateSenderPublicKey (rejects). This is by design: the callback endpoint must be pre-auth because it is the landing page after an IdP OAuth redirect.

Pomerium's HPKE receiver public key is served publicly and without authentication (internal/controlplane/http.go:82):

```go

root.Path(endpoints.PathHPKEPublicKey).Methods(http.MethodGet).Handler(

traceHandler(hpke_handlers.HPKEPublicK

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity none, availability high.

Affected software

CVE-2026-50285 is recorded against 1 package.

  • github.com/pomerium/pomerium

Timeline and source

Published on 15 July 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.

References

github.com (Web)
github.com (Web)
github.com (Package)
github.com (Web)

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE CWE-1284
Public Exploit ✅ No
Source OSV
Published 2026-07-15
Updated 2026-08-12
Modified 2026-07-15
Fix URL N/A

Affected Packages

Software From version Fixed in
github.com/pomerium/pomerium

Similar Threats

Site Security Check

Is pomerium part of your stack?

CVE-2026-50285 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.