1919using Microsoft . AspNetCore . Identity . UI . Services ;
2020using Microsoft . AspNetCore . RateLimiting ;
2121using Azure . Monitor . OpenTelemetry . AspNetCore ;
22+ using Azure . Monitor . OpenTelemetry . Profiler ;
2223using Microsoft . AspNetCore . DataProtection ;
2324using Microsoft . AspNetCore . Diagnostics ;
2425using Microsoft . AspNetCore . Diagnostics . HealthChecks ;
@@ -90,7 +91,7 @@ private static void Main(string[] args)
9091 } ) ;
9192
9293 if ( useAzureMonitor )
93- otel . UseAzureMonitor ( ) ;
94+ otel . UseAzureMonitor ( ) . AddAzureMonitorProfiler ( ) ;
9495 else if ( useOtlp )
9596 otel . UseOtlpExporter ( ) ;
9697
@@ -105,32 +106,40 @@ private static void Main(string[] args)
105106 c . Timeout = TimeSpan . FromSeconds ( 3 ) ;
106107 } ) ;
107108
108-
109+ bool hasTrustedProxyConfig = false ;
109110
110111 builder . Services . Configure < ForwardedHeadersOptions > ( options =>
111112 {
112113 options . ForwardedHeaders =
113114 ForwardedHeaders . XForwardedFor | ForwardedHeaders . XForwardedProto ;
114115
115- options . KnownIPNetworks . Clear ( ) ;
116- options . KnownProxies . Clear ( ) ;
117-
118- // Restrict trusted proxy sources to configured CIDRs.
119- // SECURITY: Set ForwardedHeaders:TrustedProxyCidrs in production to your
120- // load-balancer IP range (e.g., the Azure Container Apps ingress CIDR) to
121- // prevent X-Forwarded-For spoofing. Without this, any client can fabricate
122- // a forwarded IP and bypass IP-partitioned rate limits.
123116 var trustedCidrs = builder . Configuration
124117 . GetSection ( "ForwardedHeaders:TrustedProxyCidrs" )
125118 . Get < string [ ] > ( ) ?? [ ] ;
126119
120+ List < System . Net . IPNetwork > trustedNetworks = [ ] ;
127121 foreach ( var cidr in trustedCidrs )
128122 {
129123 if ( System . Net . IPNetwork . TryParse ( cidr , out var network ) )
130- options . KnownIPNetworks . Add ( network ) ;
124+ {
125+ trustedNetworks . Add ( network ) ;
126+ hasTrustedProxyConfig = true ;
127+ }
131128 else
132129 Console . Error . WriteLine ( $ "[WARN] ForwardedHeaders:TrustedProxyCidrs: could not parse '{ cidr } ' as an IP network — entry skipped. Check your configuration.") ;
133130 }
131+
132+ // Only replace the default loopback trust set when at least one valid
133+ // proxy CIDR is configured. Otherwise forwarded headers remain limited to
134+ // the default safe behavior instead of trusting arbitrary client-supplied
135+ // X-Forwarded-* values.
136+ if ( hasTrustedProxyConfig )
137+ {
138+ options . KnownIPNetworks . Clear ( ) ;
139+ options . KnownProxies . Clear ( ) ;
140+ foreach ( System . Net . IPNetwork network in trustedNetworks )
141+ options . KnownIPNetworks . Add ( network ) ;
142+ }
134143 } ) ;
135144
136145 ConfigurationManager configuration = builder . Configuration ;
@@ -444,8 +453,7 @@ await context.HttpContext.Response.WriteAsync(
444453 // X-Forwarded-For spoofing protection (F4) is visibly inactive until properly configured.
445454 if ( ! app . Environment . IsDevelopment ( ) )
446455 {
447- var fwdOpts = app . Services . GetRequiredService < IOptions < ForwardedHeadersOptions > > ( ) . Value ;
448- if ( fwdOpts . KnownIPNetworks . Count == 0 && fwdOpts . KnownProxies . Count == 0 )
456+ if ( ! hasTrustedProxyConfig )
449457 LogTrustedProxyCidrsNotConfigured ( app . Logger ) ;
450458 }
451459
@@ -614,6 +622,16 @@ await McpJsonRpcResponseWriter.WriteErrorAsync(
614622 LogSitemapValidationFailed ( logger , ex ) ;
615623 // Continue startup even if sitemap validation fails
616624 }
625+ catch ( ArgumentException ex )
626+ {
627+ LogSitemapValidationFailed ( logger , ex ) ;
628+ // Continue startup even if sitemap validation fails
629+ }
630+ catch ( FormatException ex )
631+ {
632+ LogSitemapValidationFailed ( logger , ex ) ;
633+ // Continue startup even if sitemap validation fails
634+ }
617635
618636 app . Run ( ) ;
619637 }
0 commit comments