Repository navigation
Security release. Closes two high-severity advisories reported through
SECURITY.md and moves the build to Go 1.27.4 for a reachable net/http crash.
Upgrading from 2.4.4 is recommended for every deployment, and is urgent for
anyone running a mixed --allowed-origins list or SCIM across more than one
organization. See the upgrade notes at the end: SCIM deprovisioning semantics
change, and org_memberships gains one nullable column.
Security
- OAuth access tokens could still be redirected to an attacker through a dotless IPv4
redirect_uri(GHSA-f9fw-76m6-wc75, high; incomplete fix of GHSA-h29v-hj44-q8cv / CVE-2026-54072) (#853).IsValidRedirectURIspecial-cased*only when it was the entire allowlist. In a mixed list such as*,https://app.example.comthe bare*fell through to the origin matcher, which re-opened it as the regex[^.]*— matching every host without a dot and no dotted one. A browser readshttp://3405803783/as203.0.113.7, so a crafted/authorizelink delivered the signed-in user's access token to any IPv4 address; the same check guards the logout, password-reset and magic-link redirects. A bare*now means "this server's own origin" wherever it appears in the list, every spelling that normalises to*(https://*,*:443,*/) is caught by one shared predicate, and a wildcard entry with no literal dot (**,*:3000) is refused outright. Affected 2.1.0 through 2.4.4, only when--allowed-originsmixes a bare*with explicit origins and the client has no registered redirect URIs. - One organization's SCIM token could deactivate a shared user in every organization (GHSA-93q4-j2hq-5qgg, high) (#854). SCIM tokens are issued per organization, but
DELETE /scim/v2/Users/{id}andPATCH active:falsewroteis_active=falseandrevoked_timestampto the global user row and deleted every session and session token, so organization A could lock a user out of organization B — andPATCH active:truecould lift B's lock in the other direction. Deprovisioning is now recorded on A's membership only; the global account is deactivated only when no other active membership remains. A deprovisioned membership also loses A's FGA grants and A's SSO sign-in, and membership existence alone no longer confers org-admin authority. Affected 2.3.0-rc.10 through 2.4.4. - Client-chosen forwarding headers no longer reach gRPC metadata (#870). The REST gateway refused 4 of the ~29 standard client-IP and host headers.
X-Forwarded-For/X-Real-Ipdecide the client IP used for rate limiting, the admin-secret lockout and audit logs, andX-Authorizer-Urldecides the host of emailed reset and magic-link URLs; all known spellings are now dropped before metadata is built. SCIMmeta.locationfor groups now comes from--urlrather than the requestHost. - Go toolchain 1.27.4 for GO-2026-6859 (HTTP/1 server crash via a
MaxBytesReaderheader race innet/http), via 1.27.3 for the advisories it patches. The release image builder is now pinned togolang:1.27.4-alpine3.24instead of the floatinggolang:1.27-alpine3.23(#871, #890). - crewjam/saml bumped from v0.5.1 to v0.6.3. v0.5.1 let a signed assertion carry a
<NameID>in a foreign namespace, which is the value SAML JIT provisioning keys on (#828, #890). govulncheck still reports GO-2026-6909 against every version because its OSV record has nofixedevent; that entry is a documented false positive in.govulncheck-allow.
Changed
- govulncheck gates CI on a written allowlist (
.govulncheck-allow,make vulncheck): any reachable finding not listed with a reason fails the build (#872). - Dependencies. Go modules upgraded across the board (AWS SDK, pgx, goose, gRPC, storage drivers). The login app and dashboard move to React 19, Vite 8 and TypeScript 7, with
baseUrldropped from both tsconfigs (#889). Alpine runtime image 3.24.3.
Upgrade notes
- SCIM deprovisioning is now per organization. An IdP that deprovisions a user who also belongs to another organization will see that user stay globally active and keep their other sessions; the user loses access to the deprovisioning organization only. A user whose last active membership is deprovisioned is deactivated globally, as before. SCIM
GETandfilter=active eq ...report the membership's state, not the global account's. - One new nullable column.
org_memberships.deprovisioned_at(unix seconds) is added by AutoMigrate on SQL backends and byALTER TABLEon Cassandra/ScyllaDB; the document stores need nothing. Absent means active, so existing members are unaffected. - Mixed
--allowed-originslists. If you rely on*beside explicit origins, the*now admits only this server's own origin as a redirect target. Add any other legitimate redirect origins explicitly. CORS behaviour for a bare*is unchanged.