Repository: dotnet/runtime
File: src/mono/wasm/host/DevServer/DevServerStartup.cs (C#)

Code before:

            endpoints.MapFallbackToFile("index.html", new StaticFileOptions
            {
                OnPrepareResponse = fileContext =>
                {
                    // Avoid caching index.html during development.
                    // When hot reload is enabled, a middleware injects a hot reload script into the response HTML.
                    // We don't want the browser to bypass this injection by using a cached response that doesn't
                    // contain the injected script. In the future, if script injection is removed in favor of a
                    // different mechanism, we can delete this comment and the line below it.
                    // See also: https://github.com/dotnet/aspnetcore/issues/45213
                    fileContext.Context.Response.Headers[HeaderNames.CacheControl] = "no-store";

                    if (options.WebServerUseCrossOriginPolicy)
                    {
                        // Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer.
                        ApplyCrossOriginPolicyHeaders(fileContext.Context);
                    }
                }
            });

            // Add general-purpose file upload endpoint when DEVSERVER_UPLOAD_PATH is set
            string? fileUploadPath = Environment.GetEnvironmentVariable("DEVSERVER_UPLOAD_PATH");
            string? fileUploadPattern = Environment.GetEnvironmentVariable("DEVSERVER_UPLOAD_PATTERN");
            if (!string.IsNullOrEmpty(fileUploadPath) && !string.IsNullOrEmpty(fileUploadPattern))
            {
                // Ensure the upload directory exists
                if (!Directory.Exists(fileUploadPath))
                {
                    Directory.CreateDirectory(fileUploadPath!);
                }
                Regex fileFilter = new Regex(fileUploadPattern!);

                // Route with filename parameter
                endpoints.MapPost("/upload/{filename}", async context =>
                {
                    try
                    {
                        // Get the filename from the route
                        var routeValues = context.Request.RouteValues;
                        string? rawFileName = routeValues["filename"]?.ToString();

                        // skip upload if no name provided or invalid
                        if (string.IsNullOrEmpty(rawFileName) || !fileFilter.IsMatch(rawFileName!))
                        {
                            return;
                        }

                        // Sanitize filename - IMPORTANT: Only use GetFileName to strip any path components
                        // This prevents directory traversal attacks like "../../../etc/passwd"
                        string fileName = Path.GetFileName(rawFileName);

Review comment (suggestion):
The endpoint is now gated on both DEVSERVER_UPLOAD_PATH and DEVSERVER_UPLOAD_PATTERN (line 124), introducing a breaking change: previously providing only DEVSERVER_UPLOAD_PATH enabled uploads. If the pattern env var is omitted, uploads silently become unavailable. Consider logging a warning when path is set but pattern is missing, or allowing a safe default pattern (e.g., ^[A-Za-z0-9_.-]+$) to preserve existing behavior.
```suggestion
            if (!string.IsNullOrEmpty(fileUploadPath))
            {
                // Use a safe default pattern if none is provided
                if (string.IsNullOrEmpty(fileUploadPattern))
                {
                    fileUploadPattern = "^[A-Za-z0-9_.-]+$";
                    // Log a warning that default pattern is being used
                    var logger = options.Logger;
                    if (logger is not null)
                    {
                        logger.LogWarning("DEVSERVER_UPLOAD_PATTERN is not set. Using default pattern: {Pattern}", fileUploadPattern);
                    }
                    else
                    {
                        Console.WriteLine($"[DevServer] Warning: DEVSERVER_UPLOAD_PATTERN is not set. Using default pattern: {fileUploadPattern}");
                    }
                }
```

Code after:

            endpoints.MapFallbackToFile("index.html", new StaticFileOptions
            {
                OnPrepareResponse = fileContext =>
                {
                    // Avoid caching index.html during development.
                    // When hot reload is enabled, a middleware injects a hot reload script into the response HTML.
                    // We don't want the browser to bypass this injection by using a cached response that doesn't
                    // contain the injected script. In the future, if script injection is removed in favor of a
                    // different mechanism, we can delete this comment and the line below it.
                    // See also: https://github.com/dotnet/aspnetcore/issues/45213
                    fileContext.Context.Response.Headers[HeaderNames.CacheControl] = "no-store";

                    if (options.WebServerUseCrossOriginPolicy)
                    {
                        // Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer.
                        ApplyCrossOriginPolicyHeaders(fileContext.Context);
                    }
                }
            });

            // Add general-purpose file upload endpoint when DEVSERVER_UPLOAD_PATH is set
            string? fileUploadPath = Environment.GetEnvironmentVariable("DEVSERVER_UPLOAD_PATH");
            string? fileUploadPattern = Environment.GetEnvironmentVariable("DEVSERVER_UPLOAD_PATTERN");
            if (!string.IsNullOrEmpty(fileUploadPath) && !string.IsNullOrEmpty(fileUploadPattern))
            {
                // Ensure the upload directory exists
                if (!Directory.Exists(fileUploadPath))
                {
                    Directory.CreateDirectory(fileUploadPath!);
                }
                Regex fileFilter;
                try
                {
                    fileFilter = new Regex(fileUploadPattern!, RegexOptions.Compiled | RegexOptions.CultureInvariant);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException($"DEVSERVER_UPLOAD_PATTERN value '{fileUploadPattern}' is not a valid regular expression: {ex.Message}", ex);
                }

                // Route with filename parameter
                endpoints.MapPost("/upload/{filename}", async context =>
                {
                    try
                    {
                        // Get the filename from the route
                        var routeValues = context.Request.RouteValues;
                        string? rawFileName = routeValues["filename"]?.ToString();

                        // skip upload if no name provided or invalid