| Version | Supported |
|---|---|
| >= 1.4.0 | Yes |
| < 1.4.0 | No |
Security updates are issued only for the 1.4.x line. Earlier versions (1.3.x and below) no longer receive fixes, including critical ones — upgrade to the latest 1.4.x to remain covered.
v1.4.2 ships SSE fan-out (Broker + PreparedEvent + ReplayStore),
WebSocket fan-out (Hub + PreparedMessage), per-client SSE
MaxQueueDepth + OnSlowClient policy, an engine-side bind retry
on transient EADDRINUSE, and a Go 1.26.3 toolchain bump.
Security-relevant changes:
-
Slow-subscriber DoS posture (SSE):
sse.Broker.SubscriberBufferbounds each subscriber's outbound queue;sse.BrokerConfig.OnSlowSubscriberdecides what happens when a queue fills (Drop,Remove, orClose). Default isDrop— leaves the stream coherent (the next event's id carries enough state forLast-Event-IDreplay to resync). Per-clientsse.Config.MaxQueueDepth+OnSlowClient(Drop/Close/Block) sit one layer below for directClient.Sendcallers. The slow-path goroutine fan-out is bounded bySlowSubscriberConcurrencyso a storm of slow callbacks cannot exhaust scheduler resources. -
Slow-conn DoS posture (WebSocket):
websocket.Hubpairs the same model —OnSlowConndefaults toClose(a dropped WS frame would corrupt the message-boundary contract, so eviction is the safer default).MaxConcurrencycaps goroutine pressure on fan-out;Hub.Closejoins every in-flight Broadcast before tearing down conns, so shutdown cannot race a still-fanning-out message. Authorization MUST happen beforeHub.Register: Hub broadcasts go to every registered connection unfiltered. UseHub.BroadcastFilterwith a pure predicate for per-conn ACL. -
PreparedMessagerejects control opcodes: control frames are bound by RFC 6455 §5.5 to ≤125 bytes and non-fragmented. The cache-and-broadcast model can't honor those constraints safely, soNewPreparedMessagereturnsErrInvalidPreparedOpcodeforOpClose/OpPing/OpPong. UseConn.WriteControlper-conn for control frames. -
Replay-store memory bounds (SSE):
sse.NewRingBuffer(maxN)is bounded by N.sse.NewKVReplayStore(KVReplayStoreConfig{TTL: …})is bounded by the supplied TTL — always set TTL to prevent unbounded growth on a long-running broker. The in-memory ID index is also soft-capped viaKVReplayStoreConfig.MaxIndex. Multi- instance ID monotonicity usesstore.Counter(RedisINCR, PostgresRETURNING id); when the KV doesn't implement Counter, the store falls back to a per-process counter and multi-instance setups will see ID collisions across instances on reconnect. -
Engine bind retry on
EADDRINUSE:engine/{epoll,iouring}retryunix.Bindup to 9 times with exponential-jittered backoff when EADDRINUSE fires on a SO_REUSEPORT-group join. The retry is bounded (~½ second worst case) and does not mask a true conflict — a persistent EADDRINUSE escapes the budget unchanged with the full bind diagnostic attached. Non-EADDRINUSE errors short-circuit immediately. The retry only smooths a documented kernel-side bind- table race observed when 12+ sockets in a single process race into the same SO_REUSEPORT group at startup. -
Go toolchain bump (1.26.2 → 1.26.3): absorbs two stdlib CVEs surfaced by govulncheck on the 1.26.2 toolchain:
GO-2026-4971: panic innet.Dialandnet.LookupPortwhen handling NUL-byte input on Windows.GO-2026-4918: infinite loop innet/http/internal/http2transport on a malformedSETTINGS_MAX_FRAME_SIZEfrom a peer. Both are fixed innet@go1.26.3/net/http@go1.26.3. Every go.mod in the repo + the loadgen sub-module pingo 1.26.3; CI workflows pin the same explicit patch version so a stale runner cache cannot regress to 1.26.2.
-
CVE-2023-44487 "HTTP/2 Rapid Reset" mitigation: unchanged from prior versions —
protocol/h2/stream/processor.go::handleRSTStreamenforces a sliding 1-second window with a 100 reset/sec rate limit and a 200 burst cap; exceeding it triggers GOAWAY withENHANCE_YOUR_CALM. The PR does not regress this path; matrix spec compliance (mage spec/ h2spec) re-validates it.
v1.4.1 ships the middleware × driver integration milestone, the dynamic worker scaler, memcached cluster failover, and a sweep of driver/middleware hot-path optimizations. Security-relevant changes:
middleware/overloadshedding ladder: 5-stage controller with CPU- queue-depth + tail-latency-EMA signals returns 503 + Retry-After at saturation. Designed to keep an overloaded process from cascading into total unavailability under DoS-shaped traffic. Defaults are conservative; the alloc-budget guard test pins the Normal-stage path at zero allocations so the middleware itself cannot become a bottleneck.
middleware/idempotencylock state machine: client-suppliedIdempotency-Keyheader is matched against astore.SetNXer-backed lock entry; concurrent duplicates while the original is in-flight return 409 (no double-execute), and replays serve the cached response for the configured TTL. Lock entries are released on handler completion or expire afterLockTimeoutso a crashed handler does not permanently block the key. Constant-time key comparison viasubtle.ConstantTimeCompare.middleware/cacheCache-Control honoring: by default, responseCache-Controldirectives (no-store,private,max-age) cap the effective TTL.Set-Cookieis excluded from stored headers by default to prevent session-cookie leakage between users.Varyheader components are folded into the cache key to prevent cross-user replay on shared keys.middleware/storeunifiedKVinterface: session, csrf, ratelimit, cache, idempotency, and JWKS cache all share the same byte-level contract.Prefixednamespace helper prevents key collisions when a single Redis / Postgres instance backs multiple middlewares; without it a CSRF token store and a session store could overwrite each other. Backed adapters: in-memory LRU (sharded), Redis (GETDELfor atomic single-use, falls back toGET+DELon Redis < 6.2 viaOldRedisCompat), Postgres (ON CONFLICTupsert + background expiry sweep), memcached.Context.SetHeaderTrust/Context.AppendRespHeader: new fast-path response-header verbs that skip the CRLF / NUL sanitize scan. Documented as caller-asserted invariants — used internally byrequestid,secure, andratelimitafter one-time validation at middleware construction. Not for user-supplied input. The fullSetHeader/AddHeaderverbs continue to sanitize.auto_cache_statementsdefault flip:Pool.OpenandNewConnectornow defaultauto_cache_statements=true(matching pgx). Cached prepared statements are scoped per connection and discarded on conn close; no cross-conn leakage. Opt out per DSN withauto_cache_statements=falsefor environments that need the simple-query semantics (e.g. server-side trigger-driven caches).- memcached cluster failover:
pickNodesuccessor walk is deterministic so a node-down event does not silently route writes to a different shard's read-replica.recordResultuses a hysteresis threshold to prevent thrashing. Stale reads during failover are surfaced as transient errors rather than silently served from a potentially-stale node.
v1.4.0 introduces the native PostgreSQL, Redis, and memcached drivers plus H2C upgrade support and the EventLoopProvider plumbing. Security posture is conservative:
- TLS not implemented:
driver/postgresrejectssslmode=require / verify-ca / verify-fullwithErrSSLNotSupportedrather than silently downgrading.sslmode=prefer / allowemit a stderr warning before downgrading to plaintext.driver/redisrejectsrediss://URLs atNewClienttime. Until first-class TLS lands, deploy over VPC, loopback, or terminate at a sidecar TLS proxy. - PG SCRAM-SHA-256 only: cleartext / MD5 / trust + SCRAM-SHA-256 (without channel binding) are supported. GSS, SSPI, Kerberos, SCRAM-SHA-256-PLUS, and other SASL mechanisms are rejected — no silent fallback to a weaker auth path.
- Driver
WithEnginedeadlock fix: when an engine'sWorkerLoopdoes not implementsyncRoundTripper, drivers fall back to direct mode (Go netpoll) instead of deadlocking. Prevents a pool-exhaustion DoS on a misconfigured server. - H2C upgrade single-token Upgrade enforcement: RFC 7540 §3.2
requires
Upgrade: h2cto be the sole token. Multi-token Upgrade headers (e.g.Upgrade: websocket, h2c) are disqualified to prevent ambiguity attacks against simultaneous WebSocket / H2 negotiation.
Per-version security notes for the 1.3.x line and earlier are preserved in the git history of this file (git log SECURITY.md). Those releases no longer receive fixes — upgrade to the latest 1.4.x to remain covered.
If you discover a security vulnerability in celeris, please report it responsibly.
Do not open a public GitHub issue for security vulnerabilities.
Instead, please email security@goceleris.dev with:
- A description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will acknowledge receipt within 48 hours and aim to provide a fix within 7 days for critical issues.
This policy covers the core github.com/goceleris/celeris module and all in-tree middleware, including:
- HTTP protocol parsing (H1, H2)
- I/O engines (io_uring, epoll, std)
- Request routing, pre-routing middleware (
Server.Pre()), and context handling - The net/http bridge adapter
- Response header sanitization (CRLF, null bytes, cookie attributes)
- Connection lifecycle management (Detach, StreamWriter, pool safety)
- Body size enforcement (MaxRequestBodySize across H1, H2, bridge)
- Callback safety (OnExpectContinue, OnConnect, OnDisconnect)
- All in-tree middleware packages (
middleware/) - The
middleware/storeunifiedKVsubstrate plus the bundled adapters (in-memory LRU, Redis, Postgres, memcached) - Native drivers:
driver/postgres,driver/redis,driver/memcached(wire-protocol parsers, auth handshakes, cluster failover state) - Sub-module middleware (
middleware/compress,middleware/metrics,middleware/otel,middleware/protobuf)
- The deprecated
github.com/goceleris/middlewaresmodule (archived, retracted) - Third-party middleware not in this repository
- Application-level vulnerabilities in user code