Skip to content

Fix/18552 cors wildcard credentials#19020

Open
Bellambharath wants to merge 4 commits intoOrchardCMS:mainfrom
Bellambharath:fix/18552-cors-wildcard-credentials
Open

Fix/18552 cors wildcard credentials#19020
Bellambharath wants to merge 4 commits intoOrchardCMS:mainfrom
Bellambharath:fix/18552-cors-wildcard-credentials

Conversation

@Bellambharath
Copy link
Copy Markdown
Contributor

Summary

  1. Treat * in AllowedOrigins as “any origin” when validating CORS policies.
  2. Prevent persisting policies that combine AllowCredentials with *.

Testing

  1. CORS Settings: AllowedOrigins = * + AllowCredentials = ON ⇒ warning shown, policy does not persist after refresh.
  2. CORS Settings: AllowedOrigins = * + AllowCredentials = OFF ⇒ policy persists after refresh.

Fixes #18552

@Piedone Piedone requested a review from hishamco March 19, 2026 20:03
@hishamco
Copy link
Copy Markdown
Member

Could you please share a GIF screenshot, before I test it myself

@gvkries
Copy link
Copy Markdown
Member

gvkries commented Mar 20, 2026

If I understand this PR correctly, the same check done by the editor UI is now also done by the CorsOptionsConfiguration. Seems reasonable, please confirm this @hishamco

@Bellambharath
Copy link
Copy Markdown
Contributor Author

Bellambharath commented Mar 20, 2026

Could you please share a GIF screenshot, before I test it myself
Here’s the GIF showing both flows:

  1. Policy “Invalid config test” (AllowedOrigins="*", AllowCredentials=ON) shows warning and disappears after refresh.
  2. Policy “Valid config test” (AllowedOrigins="*", AllowCredentials=OFF) persists after refresh.
    Valid config test
    Invalid config test

@hishamco
Copy link
Copy Markdown
Member

If I understand this PR correctly, the same check done by the editor UI is now also done by the CorsOptionsConfiguration. Seems reasonable, please confirm this @hishamco

That's what I understand, but I will check the PR

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates OrchardCore CORS handling so that a literal "*" in AllowedOrigins is treated as “any origin” for validation/loading, and prevents persisting insecure policies that combine “any origin” with credentials (fixing the lock-out scenario described in #18552).

Changes:

  • Detect "*" (with trimming) in AllowedOrigins and treat it as AllowAnyOrigin during CORS policy loading.
  • Block saving CORS policies that effectively allow any origin (including "*") while AllowCredentials is enabled.
  • Make “any origin” detection null-safe for AllowedOrigins.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
src/OrchardCore.Modules/OrchardCore.Cors/Services/CorsOptionsConfiguration.cs Adds wildcard-origin detection during policy loading and skips insecure policies.
src/OrchardCore.Modules/OrchardCore.Cors/Controllers/AdminController.cs Updates “any origin” validation to also treat "*" (trimmed) as any origin and avoids null refs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +89 to +92
}

if (corsPolicy.ExposedHeaders?.Length > 0)
{
configurePolicy.WithExposedHeaders(corsPolicy.ExposedHeaders);
}
});

if (corsPolicy.IsDefaultPolicy)
{
options.DefaultPolicyName = corsPolicy.Name;
}
}

options.DefaultPolicyName ??= corsSettings.Policies.FirstOrDefault()?.Name;
}
options.DefaultPolicyName ??= corsSettings.Policies.FirstOrDefault()?.Name;
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

options.DefaultPolicyName ??= corsSettings.Policies.FirstOrDefault()?.Name; can set the default policy name to a policy that was skipped above (e.g., invalid AllowCredentials + any-origin). That leaves DefaultPolicyName pointing at a policy that was never added via AddPolicy, which can cause runtime failures when the pipeline calls UseCors() without a policy name. Prefer selecting the first successfully-added policy name (track it during the loop), or leave DefaultPolicyName unset when no policies were loaded.

Copilot uses AI. Check for mistakes.
if (corsPolicy.AllowCredentials && allowAnyOrigin)
{
_logger.LogWarning(
"Using AllowCredentials and AllowAnyOrigin at the same time is considered a security risk, the {PolicyName} policy will not be loaded.",
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

The warning text mentions "AllowAnyOrigin" but this branch is now also triggered when AllowedOrigins contains the wildcard "" (even if AllowAnyOrigin is false). Consider rewording to refer to "any origin (including '')" so logs accurately reflect the configuration being rejected.

Suggested change
"Using AllowCredentials and AllowAnyOrigin at the same time is considered a security risk, the {PolicyName} policy will not be loaded.",
"Using AllowCredentials with any origin (including '*') is considered a security risk, the {PolicyName} policy will not be loaded.",

Copilot uses AI. Check for mistakes.
Comment on lines 19 to +25
public void Configure(CorsOptions options)
{
var corsSettings = _corsService.GetSettingsAsync().GetAwaiter().GetResult();
if (corsSettings?.Policies == null || !corsSettings.Policies.Any())
{
return;
}

foreach (var corsPolicy in corsSettings.Policies)
{
if (corsPolicy.AllowCredentials && corsPolicy.AllowAnyOrigin)
{
_logger.LogWarning("Using AllowCredentials and AllowAnyOrigin at the same time is considered a security risk, the {PolicyName} policy will not be loaded.", corsPolicy.Name);
continue;
}

options.AddPolicy(corsPolicy.Name, configurePolicy =>
{
if (corsPolicy.AllowAnyHeader)
{
configurePolicy.AllowAnyHeader();
}
else
{
configurePolicy.WithHeaders(corsPolicy.AllowedHeaders);
}
{
var corsSettings = _corsService.GetSettingsAsync().GetAwaiter().GetResult();
if (corsSettings?.Policies == null || !corsSettings.Policies.Any())
{
return;
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

Indentation for the method opening brace/body is inconsistent with the surrounding 4-space indentation in this file (e.g., the { under Configure is currently offset). Please align formatting to match the rest of the module to avoid noisy diffs going forward.

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +31
var allowAnyOrigin = corsPolicy.AllowAnyOrigin
|| corsPolicy.AllowedOrigins?.Any(origin =>
string.Equals(origin?.Trim(), CorsConstants.AnyOrigin, StringComparison.Ordinal)) == true;
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

The "any origin" detection logic is duplicated here and in AdminController.IsAnyOriginAllowed. To avoid the two drifting (e.g., different trimming/comparison rules), consider extracting a shared helper (e.g., on the settings model or a small internal utility) and reusing it in both places.

Copilot uses AI. Check for mistakes.
Comment on lines 149 to +152
private static bool IsAnyOriginAllowed(CorsPolicyViewModel corsPolicyViewModel)
=> corsPolicyViewModel.AllowAnyOrigin || corsPolicyViewModel.AllowedOrigins.Any(origin => origin == CorsConstants.AnyOrigin);
=> corsPolicyViewModel.AllowAnyOrigin
|| corsPolicyViewModel.AllowedOrigins?.Any(origin =>
string.Equals(origin?.Trim(), CorsConstants.AnyOrigin, StringComparison.Ordinal)) == true;
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This method now treats an origin entry of "" (including whitespace-trimmed) as "any origin". Since the UI warning shown on save is framed in terms of "AllowAnyOrigin", it can become confusing when the checkbox is off but "" is present in the list. Consider adjusting the user-facing warning text to reference "any origin / '*'" rather than only the checkbox name.

Copilot uses AI. Check for mistakes.
@Bellambharath
Copy link
Copy Markdown
Contributor Author

@hishamco Thanks for checking! Let me know if any changes are needed. If everything looks good, could you please approve the PR?

@hishamco
Copy link
Copy Markdown
Member

hishamco commented Apr 3, 2026

Seems Copilot suggested something :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invalid CORS config can make the site unusable

4 participants