Skip to content

Fix cors allowed origin pattern matching - #4008

Open
joemahady-comm wants to merge 1 commit into
cloudfoundry:developfrom
joemahady-comm:TNZGOV-15556
Open

Fix cors allowed origin pattern matching#4008
joemahady-comm wants to merge 1 commit into
cloudfoundry:developfrom
joemahady-comm:TNZGOV-15556

Conversation

@joemahady-comm

@joemahady-comm joemahady-comm commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Ticket: cors-allowed-origin-patterns-matched-with-find-instead-of-matches

Fix: Updated the CorsFilter to anchor (^...$) operator-supplied origin patterns during compilation and transitioned from .find() to .matches() for CORS Origin evaluations, ensuring unanchored spoofed domains are rejected while retaining intended .find() URI substring behavior.

…ith-find-instead-of-matches / uaa ai-assisted=yes

Co-authored-by: Cursor <cursoragent@cursor.com>
@joemahady-comm joemahady-comm changed the title Implement AI Scan -- MEDIUM -- cors-allowed-origin-patterns-matched-w… Fix cors allowed origin pattern matching Jul 29, 2026
@duanemay
duanemay requested a review from Copilot July 29, 2026 20:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens CORS origin validation in UAA by switching origin regex evaluation from substring matching to full-string matching, and by implicitly anchoring configured origin patterns during compilation to prevent spoofed domains from being accepted.

Changes:

  • Updated CorsFilter to validate origins with Pattern.matcher(...).matches() and to compile allowed-origin patterns with implicit ^...$ anchoring.
  • Updated login CORS MockMvc tests to use valid .* subdomain patterns for *.localhost.
  • (Tests) Continued exercising zone/path variants of logout CORS preflight behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
server/src/main/java/org/cloudfoundry/identity/uaa/security/web/CorsFilter.java Makes origin evaluation full-match and anchors configured origin regexes at compile time.
uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java Updates CORS allowed-origin test patterns to a valid .*\\.localhost form.
uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcZonePathTests.java Updates zone/path CORS allowed-origin test patterns to a valid .*\\.localhost form.
Comments suppressed due to low confidence (2)

uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java:2270

  • The allowed URI regex uses an unescaped '.' ("^/logout.do$") which also matches unintended paths like "/logoutXdo". Escaping the dot makes the test (and example configuration) match the literal ".do" suffix only.
        corsFilter.getFilter().setCorsXhrAllowedOrigins(asList("^localhost$", "^.*\\.localhost$"));
        corsFilter.getFilter().setCorsXhrAllowedUris(singletonList("^/logout.do$"));

uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcZonePathTests.java:2741

  • The allowed URI regex patterns use an unescaped '.' ("^/logout.do$", "^/z/[^/]+/logout.do$") which can match unintended URIs. Escaping the dot keeps the allowed-URI whitelist exact.
        corsFilter.getFilter().setCorsXhrAllowedOrigins(asList("^localhost$", "^.*\\.localhost$"));
        // For ZONE_PATH mode, the request path is /z/{subdomain}/logout.do, so we need to allow that pattern
        List<String> allowedUris = mode == ZoneResolutionMode.ZONE_PATH
                ? asList("^/logout.do$", "^/z/[^/]+/logout.do$")
                : singletonList("^/logout.do$");

Comment on lines +2175 to 2176
corsFilter.getFilter().setCorsXhrAllowedOrigins(asList("^localhost$", "^.*\\.localhost$"));
corsFilter.getFilter().setCorsXhrAllowedUris(singletonList("^/logout.do$"));
Comment on lines 390 to 394
if (configuration.getAllowedOrigins() != null) {
for (String allowedOrigin : configuration.getAllowedOrigins()) {
try {
configuration.getAllowedOriginPatterns().add(Pattern.compile(allowedOrigin));
configuration.getAllowedOriginPatterns().add(Pattern.compile(anchorPattern(allowedOrigin)));
log.debug("Origin '%s' is allowed for a %s CORS requests.".formatted(allowedOrigin, type));
Comment on lines +2625 to 2627
corsFilter.getFilter().setCorsXhrAllowedOrigins(asList("^localhost$", "^.*\\.localhost$"));
List<String> allowedUris = mode == ZoneResolutionMode.ZONE_PATH ? asList("^/logout.do$", "^/z/[^/]+/logout.do$") : singletonList("^/logout.do$");
corsFilter.getFilter().setCorsXhrAllowedUris(allowedUris);
Comment on lines +369 to +377
private String anchorPattern(String pattern) {
if (!pattern.startsWith("^")) {
pattern = "^" + pattern;
}
if (!pattern.endsWith("$")) {
pattern = pattern + "$";
}
return pattern;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants