See how ory compares to other vendors in security performance
Description
Ory Oathkeeper is vulnerable to an authorization bypass via HTTP path traversal. An attacker can craft a URL containing path traversal sequences (e.g. /public/../admin/secrets) that resolves to a protected path after normalization, but is matched against a permissive rule because the raw, un-normalized path is used during rule evaluation.
Preconditions
Ory Oathkeeper rules are typically configured with patterns like:
/public/<.> → allow unauthenticated access /admin/<.> → require authentication
Without path normalization, a request to /public/../admin/secrets is matched against the raw path /public/../admin/secrets. This matches the /public/<.> rule, bypassing the authentication required for /admin/secrets. After Ory Oathkeeper permits the request, the upstream server normalizes the path and serves the protected /admin/secrets resource.
Mitigation
Going forward, Ory Oathkeeper normalizes the request path before performing rule matching and before forwarding. The path /public/../admin/secrets is normalized to /admin/secrets, which correctly matches the /admin/<.> rule and triggers authentication.
As an immediate mitigation, all requests reaching Oathkeeper should be normalized, as described in the section below. Oathkeeper should be upgraded to a fixed version as soon as possible.
Defense in depth: Cleaning paths before Oathkeeper
Even after this fix, it is good practice to normalize HTTP paths in the layers in front of Oathkeeper. This provides defense in depth and protects against similar bypasses in other components. The following examples show how to achieve this with common reverse proxies and CDNs.
Nginx
Nginx normalizes paths by default when using proxypass. Alternatively, use $uri (which Nginx normalizes) rather than $requesturi in your matching rules.
Envoy
Enable the normalizepath option (available since Envoy 1.14) to normalize the path components before matching and forwarding. See the <a href="https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/httpconnectionmanager/v3/httpconnectionmanager.proto#envoy-v3-api-field-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-normalize-path" target="blank" rel="noopener noreferrer">Envoy docs on path normalization</a>.
Cloudflare
Cloudflare normalizes URLs by default. In the Cloudflare dashboard, ensure Normalize incoming URLs is enabled under Rules → Normalization. See the <a href="https://developers.cloudflare.com/rules/normalization/" target="blank" rel="noopener noreferrer">Cloudflare URL normalization docs</a>.
Ory Polis, formerly known as BoxyHQ Jackson, bridges or proxies a SAML login flow to OAuth 2.0 or OpenID Connect. Versions prior to 26.2.0 contain a DOM-based Cross-Site Scripting (XSS) vulnerability in Ory Polis's login functionality. The application improperly trusts a URL parameter (callbackUrl), which is passed to router.push. An attacker can craft a malicious link that, when opened by an authenticated user (or an unauthenticated user that later logs in), performs a client-side redirect and executes arbitrary JavaScript in the context of their browser. This could lead to credential theft, internal network pivoting, and unauthorized actions performed on behalf of the victim. Version 26.2.0 contains a patch for the issue.
Description
Ory Oathkeeper is vulnerable to authentication bypass due to cache key confusion. The oauth2introspection authenticator cache does not distinguish tokens that were validated with different introspection URLs. An attacker can therefore legitimately use a token to prime the cache, and subsequently use the same token for rules that use a different introspection server.
Preconditions
Ory Oathkeeper has to be configured with multiple oauth2introspection authenticator servers, each accepting different tokens. The authenticators also must be configured to use caching. An attacker has to have a way to gain a valid token for one of the configured introspection servers.
Mitigation
Ory Oathkeeper now includes the introspection server URL in the cache key, preventing confusion of tokens.
Update to the patched version of Ory Oathkeeper. If that is not immediately possible, disable caching for oauth2introspection authenticators.
Impact
When using client authentication method "privatekeyjwt" [[1]](https://openid.net/specs/openid-connect-core-10.html#ClientAuthentication), OpenId specification says the following about assertion jti:
A unique identifier for the token, which can be used to prevent reuse of the token. These tokens MUST only be used once, unless conditions for reuse were negotiated between the parties
Hydra does not seem to check the uniqueness of this jti value. Here is me sending the same token request twice, hence with the same jti assertion, and getting two access tokens:
$ curl --insecure --location --request POST 'https://localhost//oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'granttype=clientcredentials' \ --data-urlencode 'clientid=c001d00d-5ecc-beef-ca4e-b00b1e54a111' \ --data-urlencode 'scope=application openid' \ --data-urlencode 'clientassertiontype=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'clientassertion=eyJhb [...] jTw' {"accesstoken":"zeG0NoqOtlACl8q5J6A-TIsNegQRRUzqLZaYrQtoBZQ.VR6iUcJQYp3uj7pwvL7YtPqGhtyQe5OhnBE2KCp5pM","expiresin":3599,"scope":"application openid","tokentype":"bearer"}⏎ $ curl --insecure --location --request POST 'https://localhost//oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'granttype=clientcredentials' \ --data-urlencode 'clientid=c001d00d-5ecc-beef-ca4e-b00b1e54a111' \ --data-urlencode 'scope=application openid' \ --data-urlencode 'clientassertiontype=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'clientassertion=eyJhb [...] jTw' {"accesstoken":"wOYtgCLxLXlELORrwZlmeiqqMQ4kRzV-STU2Sollas.mwlQGCZWXN7G2IoegUe1P0Vw5iGoKrkOzOaplhMSjm4","expiresin":3599,"scope":"application openid","tokentype":"bearer"}
Patches
This issue is patched in 0.31.0.
Workarounds
Do not allow clients to use privatekeyjwt.
References
https://openid.net/specs/openid-connect-core-10.html#ClientAuthentication
In ORY Fosite (the security first OAuth2 & OpenID Connect framework for Go) before version 0.34.0, the TokenRevocationHandler ignores errors coming from the storage. This can lead to unexpected 200 status codes indicating successful revocation while the token is still valid. Whether an attacker can use this for her advantage depends on the ability to trigger errors in the store. This is fixed in version 0.34.0
ORY Oathkeeper is an Identity & Access Proxy (IAP) and Access Control Decision API that authorizes HTTP requests based on sets of Access Rules. When you make a request to an endpoint that requires the scope foo using an access token granted with that foo scope, introspection will be valid and that token will be cached. The problem comes when a second requests to an endpoint that requires the scope bar is made before the cache has expired. Whether the token is granted or not to the bar scope, introspection will be valid. A patch will be released with v0.38.12-beta.1. Per default, caching is disabled for the oauth2introspection authenticator. When caching is disabled, this vulnerability does not exist. The cache is checked in func (a AuthenticatorOAuth2Introspection) Authenticate(...). From tokenFromCache() it seems that it only validates the token expiration date, but ignores whether the token has or not the proper scopes. The vulnerability was introduced in PR #424. During review, we failed to require appropriate test coverage by the submitter which is the primary reason that the vulnerability passed the review process.
Description
Following Admin APIs in Ory Hydra are vulnerable to SQL injection due to flaws in its pagination implementation:
- listOAuth2Clients - listOAuth2ConsentSessions - listTrustedOAuth2JwtGrantIssuers
Pagination tokens are encrypted using the secret configured in secrets.pagination. If this value is not set, Hydra falls back to using secrets.system. An attacker who knows this secret can craft their own tokens, including malicious tokens that lead to SQL injection.
Preconditions
This issue can be exploited when the following conditions are met:
- One or more admin APIs listed above are directly or indirectly accessible to the attacker - The attacker can pass a raw pagination token to the affected API - The configuration value secrets.pagination is set and known to the attacker, or secrets.pagination is not set and secrets.system is known to the attacker
Impact
An attacker can execute arbitrary SQL queries through forged pagination tokens.
Mitigation
As a first line of defense, immediately configure a custom value for secrets.pagination by generating a cryptographically secure random secret, for example:
openssl rand -base64 32
Next, upgrade Hydra to the fixed version as soon as possible.
Description
The GetRelationships API in Ory Keto is vulnerable to SQL injection due to flaws in its pagination implementation.
Pagination tokens are encrypted using the secret configured in secrets.pagination. An attacker who knows this secret can craft their own tokens, including malicious tokens that lead to SQL injection. If this configuration value is not set, Keto falls back to a hard-coded default pagination encryption secret. Because this default value is publicly known, attackers can generate valid and malicious pagination tokens manually for installations where this secret is not set.
Preconditions
This issue can be exploited when all of the following conditions are met:
- GetRelationships API is directly or indirectly accessible to the attacker - The attacker can pass a raw pagination token to the affected API - The configuration value secrets.pagination is not set or known to the attacker
Impact
An attacker can execute arbitrary SQL queries through forged pagination tokens.
Mitigation
As a first line of defense, immediately configure a custom value for secrets.pagination by generating a cryptographically secure random secret, for example:
openssl rand -base64 32
Next, upgrade Keto to a fixed version as soon as possible.
Description
The ListCourierMessages Admin API in Ory Kratos is vulnerable to SQL injection due to flaws in its pagination implementation.
Pagination tokens are encrypted using the secret configured in secrets.pagination. An attacker who knows this secret can craft their own tokens, including malicious tokens that lead to SQL injection. If this configuration value is not set, Kratos falls back to a default pagination encryption secret. Because this default value is publicly known, attackers can generate valid and malicious pagination tokens manually for installations where this secret is not set.
Preconditions
This issue can be exploited when the following conditions are met:
- ListCourierMessages API is directly or indirectly accessible to the attacker - The attacker can pass a raw pagination token to the affected API - The configuration value secrets.pagination is not set or known to the attacker
Impact
An attacker can execute arbitrary SQL queries through forged pagination tokens.
Mitigation
As a first line of defense, immediately configure a custom value for secrets.pagination by generating a cryptographically secure random secret, for example:
openssl rand -base64 32
Next, upgrade Kratos to a fixed version as soon as possible.
Description
Ory Oathkeeper is often deployed behind other components like CDNs, WAFs, or reverse proxies. Depending on the setup, another component might forward the request to the Oathkeeper proxy with a different protocol (http vs. https) than the original request. In order to properly match the request against the configured rules, Oathkeeper considers the X-Forwarded-Proto header when evaluating rules. The configuration option serve.proxy.trustforwardedheaders (defaults to false) governs whether this and other X-Forwarded- headers should be trusted. Oathkeeper did not properly respect this configuration, and would always consider the X-Forwarded-Proto header.
Preconditions
In order for an attacker to abuse this, an installation of Ory Oathkeeper needs to have distinct rules for HTTP and HTTPS requests. Also, the attacker needs to be able to trigger one but not the other rule. In this scenario, the attacker can send the same request but with the X-Forwarded-Proto header in order to trigger the other rule. We do not expect many configurations to meet these preconditions.
Mitigation
It is generally recommended to drop any unexpected headers as early as possible when a request is handled, e.g. in the WAF.
Ory Oathkeeper will correctly respect the serve.proxy.trustforwardedheaders configuration going forward, thereby eliminating the attack scenario. We recommend upgrading to a fixed version even if the preconditions are not met.
ORY Fosite is a security first OAuth2 & OpenID Connect framework for Go. In Fosite from version 0.30.2 and before version 0.34.1, there is an issue in which an an attacker can override the registered redirect URL by performing an OAuth flow and requesting a redirect URL that is to the loopback adapter. Attackers can provide both custom URL query parameters to their loopback redirect URL, as well as actually overriding the host of the registered redirect URL. These attacks are only applicable in scenarios where the attacker has access over the loopback interface. This vulnerability has been patched in ORY Fosite v0.34.1.
ORY Fosite is a security first OAuth2 & OpenID Connect framework for Go. In Fosite before version 0.34.1, the OAuth 2.0 Client's registered redirect URLs and the redirect URL provided at the OAuth2 Authorization Endpoint where compared using strings.ToLower while they should have been compared with a simple string match. This allows an attacker to register a client with allowed redirect URL https://example.com/callback. Then perform an OAuth2 flow and requesting redirect URL https://example.com/CALLBACK. Instead of an error (invalid redirect URL), the browser is redirected to https://example.com/CALLBACK with a potentially successful OAuth2 response, depending on the state of the overall OAuth2 flow (the user might still deny the request for example). This vulnerability has been patched in ORY Fosite v0.34.1.
ORY Hydra before v1.0.0-rc.3+oryOS.9 has Reflected XSS via the oauth2/fallbacks/error errorhint parameter.
Impact
When using client authentication method "privatekeyjwt" [1], OpenId specification says the following about assertion jti:
A unique identifier for the token, which can be used to prevent reuse of the token. These tokens MUST only be used once, unless conditions for reuse were negotiated between the parties
Hydra does not seem to check the uniqueness of this jti value. Here is me sending the same token request twice, hence with the same jti assertion, and getting two access tokens:
$ curl --insecure --location --request POST 'https://localhost//oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'granttype=clientcredentials' \ --data-urlencode 'clientid=c001d00d-5ecc-beef-ca4e-b00b1e54a111' \ --data-urlencode 'scope=application openid' \ --data-urlencode 'clientassertiontype=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'clientassertion=eyJhb [...] jTw' {"accesstoken":"zeG0NoqOtlACl8q5J6A-TIsNegQRRUzqLZaYrQtoBZQ.VR6iUcJQYp3uj7pwvL7YtPqGhtyQe5OhnBE2KCp5pM","expiresin":3599,"scope":"application openid","tokentype":"bearer"}⏎ ~$ curl --insecure --location --request POST 'https://localhost//oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'granttype=clientcredentials' \ --data-urlencode 'clientid=c001d00d-5ecc-beef-ca4e-b00b1e54a111' \ --data-urlencode 'scope=application openid' \ --data-urlencode 'clientassertiontype=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'clientassertion=eyJhb [...] jTw' {"accesstoken":"wOYtgCLxLXlELORrwZlmeiqqMQ4kRzV-STU2Sollas.mwlQGCZWXN7G2IoegUe1P0Vw5iGoKrkOzOaplhMSjm4","expiresin":3599,"scope":"application openid","tokentype":"bearer"}
Severity
We rate the severity as medium because the following reasons make it hard to replay tokens without the patch:
- TLS protects against MITM which makes it difficult to intercept valid tokens for replay attacks - The expiry time of the JWT gives only a short window of opportunity where it could be replayed
Patches
This will be patched with v1.4.0+oryOS.17
Workarounds
Two workarounds have been identified:
- Do not allow clients to use privatekeyjwt - Use short expiry times for the JWTs
References
https://openid.net/specs/openid-connect-core-10.html#ClientAuthentication
Upstream
This issue will be resolved in the upstream repository https://github.com/ory/fosite