- DATE:
- AUTHOR:
- Ory Team
Ory Network, Ory Oathkeeper, Ory Polis, Ory Elements v26.3.6 released
Ory Network
Verify organization SSO domains with a DNS-TXT record
Workspace owners now manage their organization's SSO email domains from the workspace settings page. Adding a domain returns a DNS TXT record to publish; once Ory resolves it, the domain is verified and used to route sign-ins to the organization. Only verified domains are trusted for SSO.
Creating an organization no longer derives a domain from the owner's email address: new organizations start without domains, and owners add and verify them explicitly through the workspace settings page or the domain endpoints.
Domains that existed before this change keep working while their owners publish their records. Workspace settings flags each one as Action required and states the deadline: they must be verified by October 31, 2026, after which sign-ins for an unverified domain no longer route to the organization. Selecting Generate DNS record returns the TXT record for such a domain, so owners can complete verification at any point during the grace period.
Show the negotiated HTTP protocol version for event stream endpoints
When you create or update an HTTPS event stream, Ory now records which HTTP
protocol your endpoint negotiated during the connectivity test. The event
stream API returns this as a new read-only http_protocol_major_version field
(1 for HTTP/1.x, 2 for HTTP/2). The value is empty for SNS streams and for
paused streams, which are not connectivity-tested.
The Ory Console event streams table folds this into the stream type column,
showing HTTP, HTTP/1, or HTTP/2 for HTTPS streams. HTTP/1 streams show a
warning that recommends upgrading the endpoint to HTTP/2.
This is now available on Ory Network.
Ory Oathkeeper
Oathkeeper hardens request path handling against path-confusion attacks
Ory Oathkeeper now normalizes and validates the request URL path before matching
access rules, closing a class of path-confusion attacks that could bypass
authorization. A new security configuration section tunes this behavior, and
the defaults are secure.
Read Request path normalization and validation if you run Oathkeeper as a Decision API, place it behind another proxy, or rely on unusual path encodings.
Breaking changes
The Access Control Decision API no longer trusts incoming X-Forwarded-*
headers by default. ForwardAuth-style integrations (Traefik, NGINX, Ambassador,
Envoy) must set security.decision.x_forwarded_headers: trust to keep working.
See the
documentation
for details.
This is now available for the Ory Enterprise License and will be part of the next Ory Open Source release.
Ory Polis
Harden OIDC discovery URL fetching against SSRF
Creating or updating an OIDC SSO connection with an oidcDiscoveryUrl now
validates the fetch target, and the value is re-validated whenever it is
fetched during an authorize or callback flow.
Previously the discovery URL was stored verbatim with no scheme, host or address validation and fetched on every authorize and callback. A caller with an SSO setup link or the deployment API key could point it at an internal address — such as the cloud instance metadata service or an in-cluster service — and read a reachability and response oracle from the resulting SSO trace and error redirect.
The discovery URL now must be an HTTPS URL that does not resolve to a non-public address (loopback, link-local, carrier-grade NAT, private, unique-local, reserved and unspecified ranges for both IPv4 and IPv6, and IPv4-mapped IPv6 literals). Every outbound OIDC request — discovery, token, userinfo and JWKS — is validated at connection time, so a hostname that resolves to an internal address, or one that changes its answer between validation and the request (DNS rebinding), is blocked.
The localhost hostname is now blocked by default, so a connection owner
cannot reach services on the loopback interface of the host or pod. Local
development against an IdP on localhost is enabled automatically in a Node
development environment, or explicitly by setting
POLIS_ALLOW_LOCALHOST_OUTBOUND=true.
The in-cluster federation tunnel — which rewrites a
<slug>.projects.oryapis:8080 discovery URL to the internal hydra-public
service — keeps working unchanged; its rewrite target is a fixed,
code-controlled in-cluster service, never taken from the request. A self-hosted
deployment that does not use Ory federation can turn the tunnel off with
POLIS_DISABLE_INTERNAL_ORY_FEDERATION=true, after which a
*.projects.oryapis discovery URL is validated like any other host.
Upgrade impact
Because the discovery URL is re-validated on every authorize and callback, an
existing OIDC connection whose discovery, token, userinfo or JWKS endpoint is
plain HTTP, localhost, or a private, loopback, link-local or other non-public
address will start failing those flows immediately after upgrading. On Ory
Network this is not expected — providers are public HTTPS hosts. Self-hosted
(OEL/OSS) deployments should audit existing OIDC connections before upgrading
and re-point any such connection at a public HTTPS endpoint.
For a self-hosted deployment whose identity provider legitimately runs on an
internal network, set POLIS_ALLOW_PRIVATE_IP_OUTBOUND=true to allow HTTPS
fetches to RFC1918 and IPv6 unique-local addresses. The opt-in is narrow: HTTPS
is still required, and link-local (including the cloud metadata address),
loopback, carrier-grade NAT and reserved ranges stay blocked. An IdP on the
loopback interface uses POLIS_ALLOW_LOCALHOST_OUTBOUND=true instead.
This path is not exposed through the Ory Network gateway.
Harden SAML metadata URL fetching against SSRF
Creating or updating a SAML SSO connection with a metadataUrl now validates
the fetch target against a strict allow list before and during the request.
The previous check only rejected RFC1918 private IPv4 literals and IPv6
unique-local literals. It let through loopback, link-local (including the
cloud metadata address 169.254.169.254), carrier-grade NAT, reserved and
unspecified addresses, every IPv6 literal, and every DNS hostname, and the
fetch followed HTTP redirects without re-validating the target. A caller with
an SSO setup link or the SSO API key could use this to read internal
endpoints such as the cloud instance metadata service.
The fetch now requires an HTTPS URL, resolves the hostname and rejects any address that is not a public unicast address (covering loopback, link-local, carrier-grade NAT, private, unique-local, reserved and unspecified ranges for both IPv4 and IPv6, and IPv4-mapped IPv6 literals). Resolution happens at connection time, so a hostname that resolves to an internal address — or one that changes its answer between validation and the request (DNS rebinding) — is blocked. Redirects are no longer followed, so a public host cannot redirect the request into an internal address. Unparseable input fails closed.
The localhost hostname is blocked by default so a connection owner cannot
reach services on the loopback interface of the host or pod. Local development
against an IdP on localhost is enabled automatically in a Node development
environment, or explicitly by setting POLIS_ALLOW_LOCALHOST_OUTBOUND=true.
Upgrade impact
The previous check allowed localhost and every non-RFC1918 address, so a SAML
connection configured with a metadataUrl over plain HTTP, on localhost, or
on a private, loopback or link-local address may now be rejected when its
metadata is fetched or refreshed. On Ory Network this is not expected. Self-
hosted (OEL/OSS) deployments should audit existing SAML connections before
upgrading and re-point any such metadataUrl at a public HTTPS endpoint.
For a self-hosted identity provider on an internal network, set
POLIS_ALLOW_PRIVATE_IP_OUTBOUND=true to allow HTTPS fetches to RFC1918 and
IPv6 unique-local addresses; HTTPS is still required and link-local (including
the cloud metadata address), loopback, carrier-grade NAT and reserved ranges
stay blocked. An IdP on the loopback interface uses
POLIS_ALLOW_LOCALHOST_OUTBOUND=true instead.
This path is not exposed through the Ory Network gateway.
Add YugabyteDB support to Ory Polis
Ory Polis can now use YugabyteDB as its backing database. YugabyteDB is PostgreSQL wire-compatible, so it reuses the existing PostgreSQL driver and needs no additional dependencies. This gives self-hosted and enterprise deployments a distributed, horizontally scalable storage option alongside the existing engines (PostgreSQL, MySQL, MariaDB, Microsoft SQL Server, SQLite, CockroachDB, MongoDB, Redis, PlanetScale, and DynamoDB).
Configuration
Select YugabyteDB by setting the SQL engine and the yugabytedb type, then
point the connection URL at your YugabyteDB YSQL endpoint (default port 5433):
DB_ENGINE=sql
DB_TYPE=yugabytedb
DB_URL=postgresql://yugabyte@localhost:5433/yugabyteFix cross-tenant admin takeover through SAML admin-portal login
The Polis Admin Portal SAML login now accepts a login only when it went through
the Admin Portal's own SSO connection. Previously both the IdP-initiated
(boxyhq-saml-idplogin) and SP-initiated (boxyhq-saml) flows trusted a login
completed against any tenant's SSO connection in the deployment. An attacker
could complete a SAML login against a connection they control and receive an
Admin Portal session with read and write access to every tenant's SSO
connections and secrets.
The fix pins the resolved connection's tenant and product to the Admin Portal
defaults (_jackson_boxyhq / _jackson_admin_portal) and rejects anything
else — in the IdP-initiated provider's authorize() and in the sign-in callback
for the SP-initiated provider.
This affects self-hosted Polis (OSS) and the polis-oel chart. It is not
reachable on the Ory Network, where the gateway does not route /api/auth/**
to Polis.
Fix cross-tenant data leak in concurrent SCIM directory-sync requests
SCIM directory-sync requests could leak users and groups across tenants when two requests for different directories were processed at the same time.
The request handler bound the directory's tenant and product onto a single,
process-wide store instance that every request shared. Because that binding
was read again at each database call after intervening awaits, a second
request for a different directory could overwrite it mid-flight. A user or
group created for directory A could then be written into directory B's
namespace: directory B's directory-sync APIs would return directory A's data,
while directory A's own read returned nothing even though it received
201 Created.
The handler now binds a request-scoped copy of the store per request, so
concurrent requests can never observe one another's tenant and product. The
directory-sync admin and management API routes
(/api/v1/dsync/*, /api/admin/directory-sync/*) were bound the same way and
are migrated too, which closes a related window where a concurrent read could
redirect a "delete all webhook events" request to another tenant's namespace.
This affects self-hosted Polis; SCIM is not routed through the Ory Network
gateway.
Reject SAML responses that declare a DTD and stop leaking parser errors
The SAML assertion consumer service (POST /api/oauth/saml) parsed the
base64-decoded SAMLResponse with document type definition (DTD) processing
enabled. Because a SAML response never legitimately contains a DTD, this
exposed the XML parser to XXE-class attacks: a crafted DOCTYPE with a
SYSTEM entity produced different parser errors depending on whether a
referenced path existed, giving an unauthenticated caller a file-existence
oracle. Internal parser error text was also returned to the caller through the
polis_error cookie, which made the differential observable.
Polis now rejects any SAML response that declares a DOCTYPE/DTD before it
reaches the parser, and returns a generic error to the client. Internal error
detail is logged server-side only and is no longer disclosed to the caller: the
polis_error cookie returns a generic message for server errors, and the OAuth
error_description returned on the redirect no longer includes raw parser or
exception text. Standard OAuth error codes and OIDC provider error descriptions
are still forwarded.
Reject invalid magic-link tokens in the Polis admin portal
The admin-portal magic-link (email) sign-in accepted any token value. The
next-auth adapter looked up the stored verification token by email but returned
the record without checking that the presented token matched it. Because
next-auth treats any non-null adapter result as valid and the portal grants the
admin role to every address, an unauthenticated attacker could complete the
email callback for any address — including an administrator's — with an
arbitrary token and receive an authenticated admin session. This required
magic-link login to be enabled (NEXTAUTH_ACL set together with an SMTP host);
a default install with NEXTAUTH_ACL unset was not affected.
Polis now returns the verification token only when the presented value matches the stored one, and consumes it on that single successful use. Non-matching or missing tokens are rejected, closing the bypass (GHSA-j4rr-hrm4-hx4j).
Validate SAML SingleLogout URLs to prevent stored XSS and open redirect
SAML connection metadata is now scheme-checked on its SingleLogout (SLO)
bindings, not just its login (SSO) bindings. Previously, the
SingleLogoutService Location from an identity provider's metadata was stored
without validation and later written into the auto-submitting form and redirect
served by the unauthenticated /api/logout endpoint. A javascript: URL placed
in that field executed in the browser of anyone who opened the tenant's logout
link (stored cross-site scripting), and a crafted redirect binding could send
that visitor to an arbitrary host (open redirect).
Creating or updating a SAML connection now rejects any SLO Location that does
not use an http or https scheme, matching the check already applied to SSO
bindings. The localhost allowance in that check now also requires an http/https
scheme: previously it inspected only the host, so a javascript://localhost/...
URL parsed with hostname localhost and slipped through.
As defense in depth, the logout request builder re-checks the SLO scheme at the
point of use, so a connection that already carries a malicious SLO URL can never
emit it into the /api/logout form or redirect. Existing connections that carry
a malicious SLO URL should still be recreated or updated so the stored value is
revalidated.
Validate the post-logout redirect URL in SAML Single Logout
The unauthenticated GET /api/logout endpoint accepted a redirectUrl query
parameter and, after the identity provider completed Single Logout, redirected
the browser to it without checking it against the connection's configured
redirect URL allow-list. An attacker could send a victim a logout link with an
arbitrary redirectUrl and have Polis redirect them to an external origin
(open redirect, CWE-601).
Polis now validates redirectUrl against the connection's allow-list when the
logout request is created and rejects a disallowed or malformed value with
403 Redirect URL is not allowed. — the same check the OAuth authorize flow
applies to redirect_uri. If a stored value no longer matches the connection
resolved from the logout response, the callback falls back to the connection's
defaultRedirectUrl.
This affects self-hosted Polis (OSS and OEL). The Ory Network gateway does not
expose /saml/api/logout and is not affected.
This is now available on Ory Network, for the Ory Enterprise License, and will be part of the next Ory Open Source release.
Ory Elements
Fix duplicate-account error ignoring translations in Ory Elements
The duplicate-account error shown during registration (message 4000028) was always displayed in English when the account had no social sign-in providers. Ory Elements fell back to the raw server text whenever a message context contained an empty list, bypassing both bundled locales and custom translations.
Ory Elements now always formats messages through the active locale. Message
templates use ICU plural syntax to omit the sign-in hint sentences when the
corresponding list is empty, matching the server-side behavior. Custom
translations for message 4000028 can use the new
available_credential_types_count and available_oidc_providers_count
context values to do the same.
This is now available on Ory Network, for the Ory Enterprise License, and will be part of the next Ory Open Source release.
Ory Hydra, Ory Kratos, Ory Keto, and Ory Terraform
No significant changes in this release.