Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple X-Forwarded-Prefix header segments are not handled correctly in ForwarededHeadersMiddleware #60587

Open
1 task done
josh-romanowski opened this issue Feb 24, 2025 · 0 comments
Labels
area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares

Comments

@josh-romanowski
Copy link

josh-romanowski commented Feb 24, 2025

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When multiple values are sent for the X-Forwarded-Prefix header, e.g. /firstsegment, /secondsegment, contrary to the documentation here only the first value is consumed and the other values are not moved. The resulting PathBase is /firstsegment instead of /firstsegment/secondsegment. The documentation states that all values should be moved one after the other.

From a quick look into the ForwardedHeaderMiddleware it appears to me that in the loop in L220ff. currentValues is repeatedly replaced for all entries of sets instead of actually accumulating all the entries, despite the index being called consumedValues. sets contains two values in reverse order of the segments (first /secondsegment, then /firstsegment)

for (; entriesConsumed < sets.Length; entriesConsumed++)
{
    var set = sets[entriesConsumed];
    ...
    if (checkPrefix)
    {
        if (!string.IsNullOrEmpty(set.Prefix) && set.Prefix[0] == '/')
        {
            applyChanges = true;
            currentValues.Prefix = set.Prefix;

Thus, in L383 the incomplete PathBase is set because currentValues.Prefix only contains /firstsegment.

request.PathBase = PathString.FromUriComponent(currentValues.Prefix);

The check in L371 is also false (both forwarded.Prefix!.Length and currentValues are 2) although the header is only partially handled. Therefore, the header is not correctly trucated either.

if (forwardedPrefix!.Length > entriesConsumed)
{
    // Truncate the consumed header values
    requestHeaders[_options.ForwardedPrefixHeaderName] =
        TruncateConsumedHeaderValues(forwardedPrefix, entriesConsumed);

I did not check the logic for other headers in detail but since the handling is very similar, also similar issues might apply there.

I might be missing something in the intent of these headers, so please feel free to discuss if I misinterpret them. My use case is resolving headers behind multiple reverse proxies that are each responsible for one segment correctly.

Expected Behavior

The path base contains all segments of the header, e.g. X-Forwarded-Prefix header /firstsegment, /secondsegment results in request.PathBase /firstsegment/secondsegment.

Steps To Reproduce

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardLimit = null,
    ForwardedHeaders = ForwardedHeaders.All
});

app.Run(ctx =>
{
    Console.WriteLine(ctx.Request.PathBase);
    return Task.CompletedTask;
});

app.Run();

When I CURL the server on path / with X-Forwarded-Prefix /firstsegment, /secondsegment ctx.Request.PathBase prints /firstsegment

Exceptions (if any)

No response

.NET Version

9.0.100

Anything else?

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares label Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares
Projects
None yet
Development

No branches or pull requests

1 participant