diff --git a/NuGet.config b/NuGet.config
index d263ff7579a8..a972af091630 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -6,10 +6,10 @@
     <!--  Begin: Package sources from dotnet-extensions -->
     <!--  End: Package sources from dotnet-extensions -->
     <!--  Begin: Package sources from dotnet-efcore -->
-    <add key="darc-int-dotnet-efcore-d009555" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-d0095554/nuget/v3/index.json" />
+    <add key="darc-int-dotnet-efcore-0118cb6" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-efcore-0118cb68/nuget/v3/index.json" />
     <!--  End: Package sources from dotnet-efcore -->
     <!--  Begin: Package sources from dotnet-runtime -->
-    <add key="darc-int-dotnet-runtime-1584e49" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-1584e493/nuget/v3/index.json" />
+    <add key="darc-int-dotnet-runtime-50c4cb9" value="https://pkgs.dev.azure.com/dnceng/internal/_packaging/darc-int-dotnet-runtime-50c4cb9f/nuget/v3/index.json" />
     <!--  End: Package sources from dotnet-runtime -->
     <!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
     <add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
@@ -30,10 +30,10 @@
     <clear />
     <!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
     <!--  Begin: Package sources from dotnet-efcore -->
-    <add key="darc-int-dotnet-efcore-d009555" value="true" />
+    <add key="darc-int-dotnet-efcore-0118cb6" value="true" />
     <!--  End: Package sources from dotnet-efcore -->
     <!--  Begin: Package sources from dotnet-runtime -->
-    <add key="darc-int-dotnet-runtime-1584e49" value="true" />
+    <add key="darc-int-dotnet-runtime-50c4cb9" value="true" />
     <!--  End: Package sources from dotnet-runtime -->
     <!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
   </disabledPackageSources>
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 216f52bfdd7d..176de8a62280 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
 -->
 <Dependencies>
   <ProductDependencies>
-    <Dependency Name="dotnet-ef" Version="8.0.14">
+    <Dependency Name="dotnet-ef" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.Relational" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.Tools" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="8.0.14">
+    <Dependency Name="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-efcore</Uri>
-      <Sha>d00955545e8afc997726aead9b0e6103b1ceade6</Sha>
+      <Sha>0118cb6810a48869bf7494aabd86ef44da5940a3</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
@@ -121,9 +121,9 @@
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
       <Sha>5535e31a712343a63f5d7d796cd874e563e5ac14</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="8.0.14-servicing.25111.18">
+    <Dependency Name="Microsoft.Extensions.HostFactoryResolver.Sources" Version="8.0.15-servicing.25164.13">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
@@ -139,7 +139,7 @@
     </Dependency>
     <Dependency Name="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Extensions.Logging.Configuration" Version="8.0.1">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
@@ -185,9 +185,9 @@
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
       <Sha>5535e31a712343a63f5d7d796cd874e563e5ac14</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="8.0.14-servicing.25111.18">
+    <Dependency Name="Microsoft.Internal.Runtime.AspNetCore.Transport" Version="8.0.15-servicing.25164.13">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="Microsoft.SourceBuild.Intermediate.source-build-externals" Version="8.0.0-alpha.1.25104.1">
       <Uri>https://github.com/dotnet/source-build-externals</Uri>
@@ -207,13 +207,13 @@
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
       <Sha>2d7eea252964e69be94cb9c847b371b23e4dd470</Sha>
     </Dependency>
-    <Dependency Name="System.Diagnostics.EventLog" Version="8.0.1">
+    <Dependency Name="System.Diagnostics.EventLog" Version="8.0.2">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>81cabf2857a01351e5ab578947c7403a5b128ad1</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
-    <Dependency Name="System.DirectoryServices.Protocols" Version="8.0.0">
+    <Dependency Name="System.DirectoryServices.Protocols" Version="8.0.1">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>5535e31a712343a63f5d7d796cd874e563e5ac14</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="System.IO.Pipelines" Version="8.0.0">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
@@ -275,17 +275,17 @@
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
       <Sha>81cabf2857a01351e5ab578947c7403a5b128ad1</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.NETCore.App.Ref" Version="8.0.14">
+    <Dependency Name="Microsoft.NETCore.App.Ref" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="8.0.14">
+    <Dependency Name="Microsoft.NET.Runtime.MonoAOTCompiler.Task" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="8.0.14">
+    <Dependency Name="Microsoft.NET.Runtime.WebAssembly.Sdk" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
@@ -316,22 +316,22 @@
          Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
          All Runtime.$rid packages should have the same version.
     -->
-    <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="8.0.14">
+    <Dependency Name="Microsoft.NETCore.App.Runtime.win-x64" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.SourceBuild.Intermediate.runtime.linux-x64" Version="8.0.14-servicing.25111.18">
+    <Dependency Name="Microsoft.SourceBuild.Intermediate.runtime.linux-x64" Version="8.0.15-servicing.25164.13">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
       <SourceBuild RepoName="runtime" ManagedOnly="false" />
     </Dependency>
-    <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="8.0.14">
+    <Dependency Name="Microsoft.NETCore.App.Runtime.AOT.win-x64.Cross.browser-wasm" Version="8.0.15">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="8.0.14-servicing.25111.18">
+    <Dependency Name="Microsoft.NETCore.BrowserDebugHost.Transport" Version="8.0.15-servicing.25164.13">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Web.Xdt" Version="7.0.0-preview.22423.2">
       <Uri>https://github.com/dotnet/xdt</Uri>
@@ -368,34 +368,34 @@
   </ProductDependencies>
   <ToolsetDependencies>
     <!-- Listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
-    <Dependency Name="Microsoft.NETCore.Platforms" Version="8.0.14-servicing.25111.18">
+    <Dependency Name="Microsoft.NETCore.Platforms" Version="8.0.15-servicing.25164.13">
       <Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
-      <Sha>1584e493603cfc4e9b36b77d6d4afe97de6363f9</Sha>
+      <Sha>50c4cb9fc31c47f03eac865d7bc518af173b74b7</Sha>
     </Dependency>
     <Dependency Name="System.Drawing.Common" Version="8.0.0-rtm.23520.14">
       <Uri>https://github.com/dotnet/winforms</Uri>
       <Sha>abda8e3bfa78319363526b5a5f86863ec979940e</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.25060.1">
+    <Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.25111.4">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>c255aae7f2b128fa20a4441f0e192c3c53561621</Sha>
+      <Sha>a319ada170a54ee87c7a81e3309948e3d3ea7aca</Sha>
       <SourceBuild RepoName="arcade" ManagedOnly="true" />
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.Build.Tasks.Installers" Version="8.0.0-beta.25060.1">
+    <Dependency Name="Microsoft.DotNet.Build.Tasks.Installers" Version="8.0.0-beta.25111.4">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>c255aae7f2b128fa20a4441f0e192c3c53561621</Sha>
+      <Sha>a319ada170a54ee87c7a81e3309948e3d3ea7aca</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="8.0.0-beta.25060.1">
+    <Dependency Name="Microsoft.DotNet.Build.Tasks.Templating" Version="8.0.0-beta.25111.4">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>c255aae7f2b128fa20a4441f0e192c3c53561621</Sha>
+      <Sha>a319ada170a54ee87c7a81e3309948e3d3ea7aca</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.25060.1">
+    <Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.25111.4">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>c255aae7f2b128fa20a4441f0e192c3c53561621</Sha>
+      <Sha>a319ada170a54ee87c7a81e3309948e3d3ea7aca</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.DotNet.RemoteExecutor" Version="8.0.0-beta.25060.1">
+    <Dependency Name="Microsoft.DotNet.RemoteExecutor" Version="8.0.0-beta.25111.4">
       <Uri>https://github.com/dotnet/arcade</Uri>
-      <Sha>c255aae7f2b128fa20a4441f0e192c3c53561621</Sha>
+      <Sha>a319ada170a54ee87c7a81e3309948e3d3ea7aca</Sha>
     </Dependency>
     <Dependency Name="Microsoft.Extensions.Diagnostics.Testing" Version="8.1.0-preview.23604.1">
       <Uri>https://github.com/dotnet/extensions</Uri>
diff --git a/eng/Versions.props b/eng/Versions.props
index a4361bbfd167..5d05883df000 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,10 +8,10 @@
   <PropertyGroup Label="Version settings">
     <AspNetCoreMajorVersion>8</AspNetCoreMajorVersion>
     <AspNetCoreMinorVersion>0</AspNetCoreMinorVersion>
-    <AspNetCorePatchVersion>14</AspNetCorePatchVersion>
+    <AspNetCorePatchVersion>15</AspNetCorePatchVersion>
     <PreReleaseVersionIteration>
     </PreReleaseVersionIteration>
-    <ValidateBaseline>true</ValidateBaseline>
+    <ValidateBaseline>false</ValidateBaseline>
     <IdentityModelVersion Condition="'$(IsIdentityModelTestJob)' != 'true'">7.1.2</IdentityModelVersion>
     <IdentityModelVersion Condition="'$(IsIdentityModelTestJob)' == 'true'">7.*</IdentityModelVersion>
     <!--
@@ -67,12 +67,12 @@
   <PropertyGroup Label="Automated">
     <!-- Packages from dotnet/runtime -->
     <MicrosoftExtensionsDependencyModelVersion>8.0.2</MicrosoftExtensionsDependencyModelVersion>
-    <MicrosoftNETCoreAppRefVersion>8.0.14</MicrosoftNETCoreAppRefVersion>
-    <MicrosoftNETCoreAppRuntimewinx64Version>8.0.14</MicrosoftNETCoreAppRuntimewinx64Version>
-    <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>8.0.14</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>
-    <MicrosoftNETRuntimeWebAssemblySdkVersion>8.0.14</MicrosoftNETRuntimeWebAssemblySdkVersion>
-    <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>8.0.14</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>
-    <MicrosoftNETCoreBrowserDebugHostTransportVersion>8.0.14-servicing.25111.18</MicrosoftNETCoreBrowserDebugHostTransportVersion>
+    <MicrosoftNETCoreAppRefVersion>8.0.15</MicrosoftNETCoreAppRefVersion>
+    <MicrosoftNETCoreAppRuntimewinx64Version>8.0.15</MicrosoftNETCoreAppRuntimewinx64Version>
+    <MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>8.0.15</MicrosoftNETRuntimeMonoAOTCompilerTaskVersion>
+    <MicrosoftNETRuntimeWebAssemblySdkVersion>8.0.15</MicrosoftNETRuntimeWebAssemblySdkVersion>
+    <MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>8.0.15</MicrosoftNETCoreAppRuntimeAOTwinx64CrossbrowserwasmVersion>
+    <MicrosoftNETCoreBrowserDebugHostTransportVersion>8.0.15-servicing.25164.13</MicrosoftNETCoreBrowserDebugHostTransportVersion>
     <MicrosoftExtensionsCachingAbstractionsVersion>8.0.0</MicrosoftExtensionsCachingAbstractionsVersion>
     <MicrosoftExtensionsCachingMemoryVersion>8.0.1</MicrosoftExtensionsCachingMemoryVersion>
     <MicrosoftExtensionsConfigurationAbstractionsVersion>8.0.0</MicrosoftExtensionsConfigurationAbstractionsVersion>
@@ -93,7 +93,7 @@
     <MicrosoftExtensionsFileProvidersCompositeVersion>8.0.0</MicrosoftExtensionsFileProvidersCompositeVersion>
     <MicrosoftExtensionsFileProvidersPhysicalVersion>8.0.0</MicrosoftExtensionsFileProvidersPhysicalVersion>
     <MicrosoftExtensionsFileSystemGlobbingVersion>8.0.0</MicrosoftExtensionsFileSystemGlobbingVersion>
-    <MicrosoftExtensionsHostFactoryResolverSourcesVersion>8.0.14-servicing.25111.18</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
+    <MicrosoftExtensionsHostFactoryResolverSourcesVersion>8.0.15-servicing.25164.13</MicrosoftExtensionsHostFactoryResolverSourcesVersion>
     <MicrosoftExtensionsHostingAbstractionsVersion>8.0.1</MicrosoftExtensionsHostingAbstractionsVersion>
     <MicrosoftExtensionsHostingVersion>8.0.1</MicrosoftExtensionsHostingVersion>
     <MicrosoftExtensionsHttpVersion>8.0.1</MicrosoftExtensionsHttpVersion>
@@ -109,11 +109,11 @@
     <MicrosoftExtensionsOptionsDataAnnotationsVersion>8.0.0</MicrosoftExtensionsOptionsDataAnnotationsVersion>
     <MicrosoftExtensionsOptionsVersion>8.0.2</MicrosoftExtensionsOptionsVersion>
     <MicrosoftExtensionsPrimitivesVersion>8.0.0</MicrosoftExtensionsPrimitivesVersion>
-    <MicrosoftInternalRuntimeAspNetCoreTransportVersion>8.0.14-servicing.25111.18</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
+    <MicrosoftInternalRuntimeAspNetCoreTransportVersion>8.0.15-servicing.25164.13</MicrosoftInternalRuntimeAspNetCoreTransportVersion>
     <SystemConfigurationConfigurationManagerVersion>8.0.1</SystemConfigurationConfigurationManagerVersion>
     <SystemDiagnosticsDiagnosticSourceVersion>8.0.1</SystemDiagnosticsDiagnosticSourceVersion>
-    <SystemDiagnosticsEventLogVersion>8.0.1</SystemDiagnosticsEventLogVersion>
-    <SystemDirectoryServicesProtocolsVersion>8.0.0</SystemDirectoryServicesProtocolsVersion>
+    <SystemDiagnosticsEventLogVersion>8.0.2</SystemDiagnosticsEventLogVersion>
+    <SystemDirectoryServicesProtocolsVersion>8.0.1</SystemDirectoryServicesProtocolsVersion>
     <SystemDrawingCommonVersion>8.0.0-rtm.23520.14</SystemDrawingCommonVersion>
     <SystemIOPipelinesVersion>8.0.0</SystemIOPipelinesVersion>
     <SystemNetHttpJsonVersion>8.0.1</SystemNetHttpJsonVersion>
@@ -129,9 +129,9 @@
     <SystemThreadingAccessControlVersion>8.0.0</SystemThreadingAccessControlVersion>
     <SystemThreadingChannelsVersion>8.0.0</SystemThreadingChannelsVersion>
     <SystemThreadingRateLimitingVersion>8.0.0</SystemThreadingRateLimitingVersion>
-    <MicrosoftSourceBuildIntermediateruntimelinuxx64Version>8.0.14-servicing.25111.18</MicrosoftSourceBuildIntermediateruntimelinuxx64Version>
+    <MicrosoftSourceBuildIntermediateruntimelinuxx64Version>8.0.15-servicing.25164.13</MicrosoftSourceBuildIntermediateruntimelinuxx64Version>
     <!-- Only listed explicitly to workaround https://github.com/dotnet/cli/issues/10528 -->
-    <MicrosoftNETCorePlatformsVersion>8.0.14-servicing.25111.18</MicrosoftNETCorePlatformsVersion>
+    <MicrosoftNETCorePlatformsVersion>8.0.15-servicing.25164.13</MicrosoftNETCorePlatformsVersion>
     <MicrosoftBclAsyncInterfacesVersion>8.0.0</MicrosoftBclAsyncInterfacesVersion>
     <!-- Transitive package to provide coherency in dotnet/extensions -->
     <MicrosoftBclTimeProviderVersion>8.0.1</MicrosoftBclTimeProviderVersion>
@@ -143,14 +143,14 @@
     <MicrosoftExtensionsDiagnosticsTestingVersion>8.1.0-preview.23604.1</MicrosoftExtensionsDiagnosticsTestingVersion>
     <MicrosoftExtensionsTimeProviderTestingVersion>8.1.0-preview.23604.1</MicrosoftExtensionsTimeProviderTestingVersion>
     <!-- Packages from dotnet/efcore -->
-    <dotnetefVersion>8.0.14</dotnetefVersion>
-    <MicrosoftEntityFrameworkCoreInMemoryVersion>8.0.14</MicrosoftEntityFrameworkCoreInMemoryVersion>
-    <MicrosoftEntityFrameworkCoreRelationalVersion>8.0.14</MicrosoftEntityFrameworkCoreRelationalVersion>
-    <MicrosoftEntityFrameworkCoreSqliteVersion>8.0.14</MicrosoftEntityFrameworkCoreSqliteVersion>
-    <MicrosoftEntityFrameworkCoreSqlServerVersion>8.0.14</MicrosoftEntityFrameworkCoreSqlServerVersion>
-    <MicrosoftEntityFrameworkCoreToolsVersion>8.0.14</MicrosoftEntityFrameworkCoreToolsVersion>
-    <MicrosoftEntityFrameworkCoreVersion>8.0.14</MicrosoftEntityFrameworkCoreVersion>
-    <MicrosoftEntityFrameworkCoreDesignVersion>8.0.14</MicrosoftEntityFrameworkCoreDesignVersion>
+    <dotnetefVersion>8.0.15</dotnetefVersion>
+    <MicrosoftEntityFrameworkCoreInMemoryVersion>8.0.15</MicrosoftEntityFrameworkCoreInMemoryVersion>
+    <MicrosoftEntityFrameworkCoreRelationalVersion>8.0.15</MicrosoftEntityFrameworkCoreRelationalVersion>
+    <MicrosoftEntityFrameworkCoreSqliteVersion>8.0.15</MicrosoftEntityFrameworkCoreSqliteVersion>
+    <MicrosoftEntityFrameworkCoreSqlServerVersion>8.0.15</MicrosoftEntityFrameworkCoreSqlServerVersion>
+    <MicrosoftEntityFrameworkCoreToolsVersion>8.0.15</MicrosoftEntityFrameworkCoreToolsVersion>
+    <MicrosoftEntityFrameworkCoreVersion>8.0.15</MicrosoftEntityFrameworkCoreVersion>
+    <MicrosoftEntityFrameworkCoreDesignVersion>8.0.15</MicrosoftEntityFrameworkCoreDesignVersion>
     <!-- Packages from dotnet/roslyn -->
     <MicrosoftCodeAnalysisCommonVersion>4.8.0-7.24574.2</MicrosoftCodeAnalysisCommonVersion>
     <MicrosoftCodeAnalysisExternalAccessAspNetCoreVersion>4.8.0-7.24574.2</MicrosoftCodeAnalysisExternalAccessAspNetCoreVersion>
@@ -162,9 +162,9 @@
     <NuGetVersioningVersion>6.2.4</NuGetVersioningVersion>
     <NuGetFrameworksVersion>6.2.4</NuGetFrameworksVersion>
     <!-- Packages from dotnet/arcade -->
-    <MicrosoftDotNetBuildTasksInstallersVersion>8.0.0-beta.25060.1</MicrosoftDotNetBuildTasksInstallersVersion>
-    <MicrosoftDotNetBuildTasksTemplatingVersion>8.0.0-beta.25060.1</MicrosoftDotNetBuildTasksTemplatingVersion>
-    <MicrosoftDotNetRemoteExecutorVersion>8.0.0-beta.25060.1</MicrosoftDotNetRemoteExecutorVersion>
+    <MicrosoftDotNetBuildTasksInstallersVersion>8.0.0-beta.25111.4</MicrosoftDotNetBuildTasksInstallersVersion>
+    <MicrosoftDotNetBuildTasksTemplatingVersion>8.0.0-beta.25111.4</MicrosoftDotNetBuildTasksTemplatingVersion>
+    <MicrosoftDotNetRemoteExecutorVersion>8.0.0-beta.25111.4</MicrosoftDotNetRemoteExecutorVersion>
     <!-- Packages from dotnet/source-build-externals -->
     <MicrosoftSourceBuildIntermediatesourcebuildexternalsVersion>8.0.0-alpha.1.25104.1</MicrosoftSourceBuildIntermediatesourcebuildexternalsVersion>
     <!-- Packages from dotnet/source-build-reference-packages -->
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
index 73828dd30d31..4f0546dce120 100644
--- a/eng/common/sdk-task.ps1
+++ b/eng/common/sdk-task.ps1
@@ -64,7 +64,7 @@ try {
       $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty
     }
     if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) {
-      $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.8.1-2" -MemberType NoteProperty
+      $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.12.0" -MemberType NoteProperty
     }
     if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") {
         $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true
diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml
index 9f4c600ac094..41bbb915736a 100644
--- a/eng/common/templates/steps/source-build.yml
+++ b/eng/common/templates/steps/source-build.yml
@@ -44,7 +44,7 @@ steps:
     # in the default public locations.
     internalRuntimeDownloadArgs=
     if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then
-      internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://ci.dot.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://ci.dot.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)'
+      internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)'
     fi
 
     buildConfig=Release
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 60352ede194e..a00577ed17aa 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -384,8 +384,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
 
   # If the version of msbuild is going to be xcopied,
   # use this version. Version matches a package here:
-  # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/RoslynTools.MSBuild/versions/17.8.1-2
-  $defaultXCopyMSBuildVersion = '17.8.1-2'
+  # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/RoslynTools.MSBuild/versions/17.12.0
+  $defaultXCopyMSBuildVersion = '17.12.0'
 
   if (!$vsRequirements) {
     if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {
diff --git a/global.json b/global.json
index 3002fbd32cbe..9d3930333424 100644
--- a/global.json
+++ b/global.json
@@ -25,8 +25,8 @@
   },
   "msbuild-sdks": {
     "Yarn.MSBuild": "1.22.19",
-    "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.25060.1",
-    "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.25060.1"
+    "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.25111.4",
+    "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.25111.4"
   },
   "native-tools": {
     "jdk": "latest"
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/main.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/main.cpp
index 86c764df8533..3e1bbc1add95 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/main.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/main.cpp
@@ -8,5 +8,5 @@ DECLARE_DEBUG_PRINT_OBJECT2("tests", ASPNETCORE_DEBUG_FLAG_INFO | ASPNETCORE_DEB
 int wmain(int argc, wchar_t* argv[])
 {
     ::testing::InitGoogleTest(&argc, argv);
-    RUN_ALL_TESTS();
+    return RUN_ALL_TESTS();
 }
diff --git a/src/Servers/Kestrel/Core/src/CoreStrings.resx b/src/Servers/Kestrel/Core/src/CoreStrings.resx
index 2c7c3e8ef18d..68908731bf54 100644
--- a/src/Servers/Kestrel/Core/src/CoreStrings.resx
+++ b/src/Servers/Kestrel/Core/src/CoreStrings.resx
@@ -734,4 +734,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
   <data name="NeedHttpsConfigurationToBindHttpsAddresses" xml:space="preserve">
     <value>Call UseKestrelHttpsConfiguration() on IWebHostBuilder to automatically enable HTTPS when an https:// address is used.</value>
   </data>
-</root>
+  <data name="Http3ControlStreamFrameTooLarge" xml:space="preserve">
+    <value>The client sent a {frameType} frame to a control stream that was too large.</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/src/Servers/Kestrel/Core/src/Http3Limits.cs b/src/Servers/Kestrel/Core/src/Http3Limits.cs
index 0d7801e48bf8..b6556557a340 100644
--- a/src/Servers/Kestrel/Core/src/Http3Limits.cs
+++ b/src/Servers/Kestrel/Core/src/Http3Limits.cs
@@ -37,7 +37,7 @@ internal int HeaderTableSize
     /// <summary>
     /// Indicates the size of the maximum allowed size of a request header field sequence. This limit applies to both name and value sequences in their compressed and uncompressed representations.
     /// <para>
-    /// Value must be greater than 0, defaults to 2^14 (16,384).
+    /// Value must be greater than 0, defaults to 2^15 (32,768).
     /// </para>
     /// </summary>
     public int MaxRequestHeaderFieldSize
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Data.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Data.cs
index 95dbbcb8e4d5..ce1e9b0db815 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Data.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Data.cs
@@ -7,7 +7,7 @@ internal partial class Http3RawFrame
 {
     public void PrepareData()
     {
-        Length = 0;
+        RemainingLength = 0;
         Type = Http3FrameType.Data;
     }
 }
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.GoAway.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.GoAway.cs
index fe2eb3a6e42e..de1a73cb830e 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.GoAway.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.GoAway.cs
@@ -7,7 +7,7 @@ internal partial class Http3RawFrame
 {
     public void PrepareGoAway()
     {
-        Length = 0;
+        RemainingLength = 0;
         Type = Http3FrameType.GoAway;
     }
 }
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Headers.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Headers.cs
index bcf65929694d..11e8c971ff21 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Headers.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Headers.cs
@@ -7,7 +7,7 @@ internal partial class Http3RawFrame
 {
     public void PrepareHeaders()
     {
-        Length = 0;
+        RemainingLength = 0;
         Type = Http3FrameType.Headers;
     }
 }
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Settings.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Settings.cs
index 9e74e07db5b8..03ed2a670250 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Settings.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.Settings.cs
@@ -7,7 +7,7 @@ internal partial class Http3RawFrame
 {
     public void PrepareSettings()
     {
-        Length = 0;
+        RemainingLength = 0;
         Type = Http3FrameType.Settings;
     }
 }
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.cs
index 076b9640d0bb..5839d515524c 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Frames/Http3RawFrame.cs
@@ -9,7 +9,7 @@ namespace System.Net.Http;
 internal partial class Http3RawFrame
 #pragma warning restore CA1852 // Seal internal types
 {
-    public long Length { get; set; }
+    public long RemainingLength { get; set; }
 
     public Http3FrameType Type { get; internal set; }
 
@@ -17,6 +17,6 @@ internal partial class Http3RawFrame
 
     public override string ToString()
     {
-        return $"{FormattedType} Length: {Length}";
+        return $"{FormattedType} Length: {RemainingLength}";
     }
 }
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3ControlStream.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3ControlStream.cs
index 599a55f50212..5bb9452a5da1 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3ControlStream.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3ControlStream.cs
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Buffers;
+using System.Diagnostics;
 using System.Globalization;
 using System.IO.Pipelines;
 using System.Net.Http;
@@ -19,13 +20,18 @@ internal abstract class Http3ControlStream : IHttp3Stream, IThreadPoolWorkItem
     private const int EncoderStreamTypeId = 2;
     private const int DecoderStreamTypeId = 3;
 
+    // Arbitrarily chosen max frame length
+    // ControlStream frames currently are very small, either a single variable length integer (max 8 bytes), two variable length integers,
+    // or in the case of SETTINGS a small collection of two variable length integers
+    // We'll use a generous value of 10k in case new optional frame(s) are added that might be a little larger than the current frames.
+    private const int MaxFrameSize = 10_000;
+
     private readonly Http3FrameWriter _frameWriter;
     private readonly Http3StreamContext _context;
     private readonly Http3PeerSettings _serverPeerSettings;
     private readonly IStreamIdFeature _streamIdFeature;
     private readonly IStreamClosedFeature _streamClosedFeature;
     private readonly IProtocolErrorCodeFeature _errorCodeFeature;
-    private readonly Http3RawFrame _incomingFrame = new Http3RawFrame();
     private volatile int _isClosed;
     private long _headerType;
     private readonly object _completionLock = new();
@@ -159,9 +165,9 @@ private async ValueTask<long> TryReadStreamHeaderAsync()
             {
                 if (!readableBuffer.IsEmpty)
                 {
-                    var id = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out examined);
-                    if (id != -1)
+                    if (VariableLengthIntegerHelper.TryGetInteger(readableBuffer, out consumed, out var id))
                     {
+                        examined = consumed;
                         return id;
                     }
                 }
@@ -240,6 +246,8 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
         }
         finally
         {
+            await _context.StreamContext.DisposeAsync();
+
             ApplyCompletionFlag(StreamCompletionFlags.Completed);
             _context.StreamLifetimeHandler.OnStreamCompleted(this);
         }
@@ -247,6 +255,8 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
 
     private async Task HandleControlStream()
     {
+        var incomingFrame = new Http3RawFrame();
+        var isContinuedFrame = false;
         while (_isClosed == 0)
         {
             var result = await Input.ReadAsync();
@@ -259,12 +269,33 @@ private async Task HandleControlStream()
                 if (!readableBuffer.IsEmpty)
                 {
                     // need to kick off httpprotocol process request async here.
-                    while (Http3FrameReader.TryReadFrame(ref readableBuffer, _incomingFrame, out var framePayload))
+                    while (Http3FrameReader.TryReadFrame(ref readableBuffer, incomingFrame, isContinuedFrame, out var framePayload))
                     {
-                        Log.Http3FrameReceived(_context.ConnectionId, _streamIdFeature.StreamId, _incomingFrame);
-
-                        consumed = examined = framePayload.End;
-                        await ProcessHttp3ControlStream(framePayload);
+                        Debug.Assert(incomingFrame.RemainingLength >= framePayload.Length);
+
+                        // Only log when parsing the beginning of the frame
+                        if (!isContinuedFrame)
+                        {
+                            Log.Http3FrameReceived(_context.ConnectionId, _streamIdFeature.StreamId, incomingFrame);
+                        }
+
+                        examined = framePayload.End;
+                        await ProcessHttp3ControlStream(incomingFrame, isContinuedFrame, framePayload, out consumed);
+
+                        if (incomingFrame.RemainingLength == framePayload.Length)
+                        {
+                            Debug.Assert(framePayload.Slice(0, consumed).Length == framePayload.Length);
+
+                            incomingFrame.RemainingLength = 0;
+                            isContinuedFrame = false;
+                        }
+                        else
+                        {
+                            incomingFrame.RemainingLength -= framePayload.Slice(0, consumed).Length;
+                            isContinuedFrame = true;
+
+                            Debug.Assert(incomingFrame.RemainingLength > 0);
+                        }
                     }
                 }
 
@@ -294,56 +325,71 @@ private async ValueTask HandleEncodingDecodingTask()
         }
     }
 
-    private ValueTask ProcessHttp3ControlStream(in ReadOnlySequence<byte> payload)
+    private ValueTask ProcessHttp3ControlStream(Http3RawFrame incomingFrame, bool isContinuedFrame, in ReadOnlySequence<byte> payload, out SequencePosition consumed)
     {
-        switch (_incomingFrame.Type)
+        // default to consuming the entire payload, this is so that we don't need to set consumed from all the frame types that aren't implemented yet.
+        // individual frame types can set consumed if they're implemented and want to be able to partially consume the payload.
+        consumed = payload.End;
+        switch (incomingFrame.Type)
         {
             case Http3FrameType.Data:
             case Http3FrameType.Headers:
             case Http3FrameType.PushPromise:
-                // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-7.2
-                throw new Http3ConnectionErrorException(CoreStrings.FormatHttp3ErrorUnsupportedFrameOnControlStream(_incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame);
+                // https://www.rfc-editor.org/rfc/rfc9114.html#section-8.1-2.12.1
+                throw new Http3ConnectionErrorException(CoreStrings.FormatHttp3ErrorUnsupportedFrameOnControlStream(incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame);
             case Http3FrameType.Settings:
-                return ProcessSettingsFrameAsync(payload);
+                CheckMaxFrameSize(incomingFrame);
+                return ProcessSettingsFrameAsync(isContinuedFrame, payload, out consumed);
             case Http3FrameType.GoAway:
-                return ProcessGoAwayFrameAsync();
+                return ProcessGoAwayFrameAsync(isContinuedFrame, incomingFrame, payload, out consumed);
             case Http3FrameType.CancelPush:
-                return ProcessCancelPushFrameAsync();
+                return ProcessCancelPushFrameAsync(incomingFrame, payload, out consumed);
             case Http3FrameType.MaxPushId:
-                return ProcessMaxPushIdFrameAsync();
+                return ProcessMaxPushIdFrameAsync(incomingFrame, payload, out consumed);
             default:
-                return ProcessUnknownFrameAsync(_incomingFrame.Type);
+                CheckMaxFrameSize(incomingFrame);
+                return ProcessUnknownFrameAsync(incomingFrame.Type);
         }
-    }
 
-    private ValueTask ProcessSettingsFrameAsync(ReadOnlySequence<byte> payload)
-    {
-        if (_haveReceivedSettingsFrame)
+        static void CheckMaxFrameSize(Http3RawFrame http3RawFrame)
         {
-            // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-settings
-            throw new Http3ConnectionErrorException(CoreStrings.Http3ErrorControlStreamMultipleSettingsFrames, Http3ErrorCode.UnexpectedFrame);
+            // Not part of the RFC, but it's a good idea to limit the size of frames when we know they're supposed to be small.
+            if (http3RawFrame.RemainingLength >= MaxFrameSize)
+            {
+                throw new Http3ConnectionErrorException(CoreStrings.FormatHttp3ControlStreamFrameTooLarge(http3RawFrame.FormattedType), Http3ErrorCode.FrameError);
+            }
         }
+    }
 
-        _haveReceivedSettingsFrame = true;
-        _streamClosedFeature.OnClosed(static state =>
+    private ValueTask ProcessSettingsFrameAsync(bool isContinuedFrame, ReadOnlySequence<byte> payload, out SequencePosition consumed)
+    {
+        if (!isContinuedFrame)
         {
-            var stream = (Http3ControlStream)state!;
-            stream.OnStreamClosed();
-        }, this);
+            if (_haveReceivedSettingsFrame)
+            {
+                // https://www.rfc-editor.org/rfc/rfc9114.html#section-7.2.4
+                throw new Http3ConnectionErrorException(CoreStrings.Http3ErrorControlStreamMultipleSettingsFrames, Http3ErrorCode.UnexpectedFrame);
+            }
+
+            _haveReceivedSettingsFrame = true;
+            _streamClosedFeature.OnClosed(static state =>
+            {
+                var stream = (Http3ControlStream)state!;
+                stream.OnStreamClosed();
+            }, this);
+        }
 
         while (true)
         {
-            var id = VariableLengthIntegerHelper.GetInteger(payload, out var consumed, out _);
-            if (id == -1)
+            if (!VariableLengthIntegerHelper.TryGetInteger(payload, out consumed, out var id))
             {
                 break;
             }
 
-            payload = payload.Slice(consumed);
-
-            var value = VariableLengthIntegerHelper.GetInteger(payload, out consumed, out _);
-            if (value == -1)
+            if (!VariableLengthIntegerHelper.TryGetInteger(payload.Slice(consumed), out consumed, out var value))
             {
+                // Reset consumed to very start even though we successfully read 1 varint. It's because we want to keep the id for when we have the value as well.
+                consumed = payload.Start;
                 break;
             }
 
@@ -382,37 +428,48 @@ private void ProcessSetting(long id, long value)
         }
     }
 
-    private ValueTask ProcessGoAwayFrameAsync()
+    private ValueTask ProcessGoAwayFrameAsync(bool isContinuedFrame, Http3RawFrame incomingFrame, ReadOnlySequence<byte> payload, out SequencePosition consumed)
     {
-        EnsureSettingsFrame(Http3FrameType.GoAway);
+        // https://www.rfc-editor.org/rfc/rfc9114.html#name-goaway
+
+        // We've already triggered RequestClose since isContinuedFrame is only true
+        // after we've already parsed the frame type and called the processing function at least once.
+        if (!isContinuedFrame)
+        {
+            EnsureSettingsFrame(Http3FrameType.GoAway);
 
-        // StopProcessingNextRequest must be called before RequestClose to ensure it's considered client initiated.
-        _context.Connection.StopProcessingNextRequest(serverInitiated: false);
-        _context.ConnectionContext.Features.Get<IConnectionLifetimeNotificationFeature>()?.RequestClose();
+            // StopProcessingNextRequest must be called before RequestClose to ensure it's considered client initiated.
+            _context.Connection.StopProcessingNextRequest(serverInitiated: false);
+            _context.ConnectionContext.Features.Get<IConnectionLifetimeNotificationFeature>()?.RequestClose();
+        }
 
-        // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-goaway
-        // PUSH is not implemented so nothing to do.
+        // PUSH is not implemented but we still want to parse the frame to do error checking
+        ParseVarIntWithFrameLengthValidation(incomingFrame, payload, out consumed);
 
         // TODO: Double check the connection remains open.
         return default;
     }
 
-    private ValueTask ProcessCancelPushFrameAsync()
+    private ValueTask ProcessCancelPushFrameAsync(Http3RawFrame incomingFrame, ReadOnlySequence<byte> payload, out SequencePosition consumed)
     {
+        // https://www.rfc-editor.org/rfc/rfc9114.html#section-7.2.3
+
         EnsureSettingsFrame(Http3FrameType.CancelPush);
 
-        // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-cancel_push
-        // PUSH is not implemented so nothing to do.
+        // PUSH is not implemented but we still want to parse the frame to do error checking
+        ParseVarIntWithFrameLengthValidation(incomingFrame, payload, out consumed);
 
         return default;
     }
 
-    private ValueTask ProcessMaxPushIdFrameAsync()
+    private ValueTask ProcessMaxPushIdFrameAsync(Http3RawFrame incomingFrame, ReadOnlySequence<byte> payload, out SequencePosition consumed)
     {
+        // https://www.rfc-editor.org/rfc/rfc9114.html#section-7.2.7
+
         EnsureSettingsFrame(Http3FrameType.MaxPushId);
 
-        // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-cancel_push
-        // PUSH is not implemented so nothing to do.
+        // PUSH is not implemented but we still want to parse the frame to do error checking
+        ParseVarIntWithFrameLengthValidation(incomingFrame, payload, out consumed);
 
         return default;
     }
@@ -426,6 +483,23 @@ private ValueTask ProcessUnknownFrameAsync(Http3FrameType frameType)
         return default;
     }
 
+    // Used for frame types that aren't (fully) implemented yet and contain a single var int as part of their framing. (CancelPush, MaxPushId, GoAway)
+    // We want to throw an error if the length field of the frame is larger than the spec defined format of the frame.
+    private static void ParseVarIntWithFrameLengthValidation(Http3RawFrame incomingFrame, ReadOnlySequence<byte> payload, out SequencePosition consumed)
+    {
+        if (!VariableLengthIntegerHelper.TryGetInteger(payload, out consumed, out _))
+        {
+            return;
+        }
+
+        if (incomingFrame.RemainingLength > payload.Slice(0, consumed).Length)
+        {
+            // https://www.rfc-editor.org/rfc/rfc9114.html#section-10.8
+            // An implementation MUST ensure that the length of a frame exactly matches the length of the fields it contains.
+            throw new Http3ConnectionErrorException(CoreStrings.FormatHttp3ControlStreamFrameTooLarge(Http3Formatting.ToFormattedType(incomingFrame.Type)), Http3ErrorCode.FrameError);
+        }
+    }
+
     private void EnsureSettingsFrame(Http3FrameType frameType)
     {
         if (!_haveReceivedSettingsFrame)
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameReader.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameReader.cs
index 66740c710f10..2de0472483a1 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameReader.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameReader.cs
@@ -19,36 +19,44 @@ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
         |                       Frame Payload (*)                     ...
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */
-    internal static bool TryReadFrame(ref ReadOnlySequence<byte> readableBuffer, Http3RawFrame frame, out ReadOnlySequence<byte> framePayload)
+    // Reads and returns partial frames, don't rely on the frame being complete when using this method
+    // Set isContinuedFrame to true when expecting to read more of the previous frame
+    internal static bool TryReadFrame(ref ReadOnlySequence<byte> readableBuffer, Http3RawFrame frame, bool isContinuedFrame, out ReadOnlySequence<byte> framePayload)
     {
         framePayload = ReadOnlySequence<byte>.Empty;
-        SequencePosition consumed;
+        SequencePosition consumed = readableBuffer.Start;
+        var length = frame.RemainingLength;
 
-        var type = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out _);
-        if (type == -1)
+        if (!isContinuedFrame)
         {
-            return false;
-        }
+            if (!VariableLengthIntegerHelper.TryGetInteger(readableBuffer, out consumed, out var type))
+            {
+                return false;
+            }
 
-        var firstLengthBuffer = readableBuffer.Slice(consumed);
+            var firstLengthBuffer = readableBuffer.Slice(consumed);
 
-        var length = VariableLengthIntegerHelper.GetInteger(firstLengthBuffer, out consumed, out _);
+            if (!VariableLengthIntegerHelper.TryGetInteger(firstLengthBuffer, out consumed, out length))
+            {
+                return false;
+            }
 
-        // Make sure the whole frame is buffered
-        if (length == -1)
-        {
-            return false;
+            frame.RemainingLength = length;
+            frame.Type = (Http3FrameType)type;
         }
 
         var startOfFramePayload = readableBuffer.Slice(consumed);
-        if (startOfFramePayload.Length < length)
+
+        // Get all the available bytes or the rest of the frame whichever is less
+        length = Math.Min(startOfFramePayload.Length, length);
+
+        // If we were expecting a non-empty payload, but haven't received any of it yet,
+        // there is nothing to process until we wait for more data.
+        if (length == 0 && frame.RemainingLength != 0)
         {
             return false;
         }
 
-        frame.Length = length;
-        frame.Type = (Http3FrameType)type;
-
         // The remaining payload minus the extra fields
         framePayload = startOfFramePayload.Slice(0, length);
         readableBuffer = readableBuffer.Slice(framePayload.End);
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameWriter.cs
index dbcd774af4d6..44034fa365f2 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameWriter.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3FrameWriter.cs
@@ -121,7 +121,7 @@ internal Task WriteSettingsAsync(List<Http3PeerSetting> settings)
         WriteSettings(settings, buffer);
 
         // Advance pipe writer and flush
-        _outgoingFrame.Length = totalLength;
+        _outgoingFrame.RemainingLength = totalLength;
         _outputWriter.Advance(totalLength);
 
         return _outputWriter.FlushAsync().GetAsTask();
@@ -186,7 +186,7 @@ private void WriteDataUnsynchronized(in ReadOnlySequence<byte> data, long dataLe
             return;
         }
 
-        _outgoingFrame.Length = (int)dataLength;
+        _outgoingFrame.RemainingLength = (int)dataLength;
 
         WriteHeaderUnsynchronized();
 
@@ -209,7 +209,7 @@ void SplitAndWriteDataUnsynchronized(in ReadOnlySequence<byte> data, long dataLe
             do
             {
                 var currentData = remainingData.Slice(0, dataPayloadLength);
-                _outgoingFrame.Length = dataPayloadLength;
+                _outgoingFrame.RemainingLength = dataPayloadLength;
 
                 WriteHeaderUnsynchronized();
 
@@ -223,7 +223,7 @@ void SplitAndWriteDataUnsynchronized(in ReadOnlySequence<byte> data, long dataLe
 
             } while (dataLength > dataPayloadLength);
 
-            _outgoingFrame.Length = (int)dataLength;
+            _outgoingFrame.RemainingLength = (int)dataLength;
 
             WriteHeaderUnsynchronized();
 
@@ -240,7 +240,7 @@ internal ValueTask<FlushResult> WriteGoAway(long id)
 
         var length = VariableLengthIntegerHelper.GetByteCount(id);
 
-        _outgoingFrame.Length = length;
+        _outgoingFrame.RemainingLength = length;
 
         WriteHeaderUnsynchronized();
 
@@ -253,10 +253,10 @@ internal ValueTask<FlushResult> WriteGoAway(long id)
     private void WriteHeaderUnsynchronized()
     {
         _log.Http3FrameSending(_connectionId, _streamIdFeature.StreamId, _outgoingFrame);
-        var headerLength = WriteHeader(_outgoingFrame.Type, _outgoingFrame.Length, _outputWriter);
+        var headerLength = WriteHeader(_outgoingFrame.Type, _outgoingFrame.RemainingLength, _outputWriter);
 
         // We assume the payload will be written prior to the next flush.
-        _unflushedBytes += headerLength + _outgoingFrame.Length;
+        _unflushedBytes += headerLength + _outgoingFrame.RemainingLength;
     }
 
     public ValueTask<FlushResult> Write100ContinueAsync()
@@ -269,7 +269,7 @@ public ValueTask<FlushResult> Write100ContinueAsync()
             }
 
             _outgoingFrame.PrepareHeaders();
-            _outgoingFrame.Length = ContinueBytes.Length;
+            _outgoingFrame.RemainingLength = ContinueBytes.Length;
             WriteHeaderUnsynchronized();
             _outputWriter.Write(ContinueBytes);
             return TimeFlushUnsynchronizedAsync();
@@ -394,7 +394,7 @@ private void FinishWritingHeaders(int payloadLength, bool done)
 
         ValidateHeadersTotalSize();
 
-        _outgoingFrame.Length = _headerEncodingBuffer.WrittenCount;
+        _outgoingFrame.RemainingLength = _headerEncodingBuffer.WrittenCount;
         WriteHeaderUnsynchronized();
         _outputWriter.Write(_headerEncodingBuffer.WrittenSpan);
 
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3PendingStream.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3PendingStream.cs
index b6db0bb810db..7dabb9654c56 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3PendingStream.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3PendingStream.cs
@@ -60,8 +60,7 @@ public async ValueTask<long> ReadNextStreamHeaderAsync(Http3StreamContext contex
 
                 if (!readableBuffer.IsEmpty)
                 {
-                    var value = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out _);
-                    if (value != -1)
+                    if (VariableLengthIntegerHelper.TryGetInteger(readableBuffer, out consumed, out var value))
                     {
                         if (!advanceOn.HasValue || value == (long)advanceOn)
                         {
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs
index 61625f180cd2..17178ffbf133 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs
@@ -59,7 +59,6 @@ internal abstract partial class Http3Stream : HttpProtocol, IHttp3Stream, IHttpS
     private readonly object _completionLock = new();
 
     protected RequestHeaderParsingState _requestHeaderParsingState;
-    protected readonly Http3RawFrame _incomingFrame = new();
 
     public bool EndStreamReceived => (_completionState & StreamCompletionFlags.EndStreamReceived) == StreamCompletionFlags.EndStreamReceived;
     public bool IsAborted => (_completionState & StreamCompletionFlags.Aborted) == StreamCompletionFlags.Aborted;
@@ -607,6 +606,8 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
 
         try
         {
+            var incomingFrame = new Http3RawFrame();
+            var isContinuedFrame = false;
             while (_isClosed == 0)
             {
                 var result = await Input.ReadAsync();
@@ -618,12 +619,19 @@ public async Task ProcessRequestAsync<TContext>(IHttpApplication<TContext> appli
                 {
                     if (!readableBuffer.IsEmpty)
                     {
-                        while (Http3FrameReader.TryReadFrame(ref readableBuffer, _incomingFrame, out var framePayload))
+                        while (Http3FrameReader.TryReadFrame(ref readableBuffer, incomingFrame, isContinuedFrame, out var framePayload))
                         {
-                            Log.Http3FrameReceived(ConnectionId, _streamIdFeature.StreamId, _incomingFrame);
+                            // Only log when parsing the beginning of the frame
+                            if (!isContinuedFrame)
+                            {
+                                Log.Http3FrameReceived(ConnectionId, _streamIdFeature.StreamId, incomingFrame);
+                            }
 
                             consumed = examined = framePayload.End;
-                            await ProcessHttp3Stream(application, framePayload, result.IsCompleted && readableBuffer.IsEmpty);
+                            await ProcessHttp3Stream(application, incomingFrame, isContinuedFrame, framePayload, result.IsCompleted && readableBuffer.IsEmpty);
+
+                            incomingFrame.RemainingLength -= framePayload.Length;
+                            isContinuedFrame = incomingFrame.RemainingLength > 0 ? true : false;
                         }
                     }
 
@@ -746,22 +754,23 @@ private ValueTask OnEndStreamReceived()
         return RequestBodyPipe.Writer.CompleteAsync();
     }
 
-    private Task ProcessHttp3Stream<TContext>(IHttpApplication<TContext> application, in ReadOnlySequence<byte> payload, bool isCompleted) where TContext : notnull
+    private Task ProcessHttp3Stream<TContext>(IHttpApplication<TContext> application, Http3RawFrame incomingFrame, bool isContinuedFrame,
+        in ReadOnlySequence<byte> payload, bool isCompleted) where TContext : notnull
     {
-        return _incomingFrame.Type switch
+        return incomingFrame.Type switch
         {
             Http3FrameType.Data => ProcessDataFrameAsync(payload),
-            Http3FrameType.Headers => ProcessHeadersFrameAsync(application, payload, isCompleted),
+            Http3FrameType.Headers => ProcessHeadersFrameAsync(application, incomingFrame, isContinuedFrame, payload, isCompleted),
             // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-7.2.4
             // These frames need to be on a control stream
             Http3FrameType.Settings or
             Http3FrameType.CancelPush or
             Http3FrameType.GoAway or
             Http3FrameType.MaxPushId => throw new Http3ConnectionErrorException(
-                CoreStrings.FormatHttp3ErrorUnsupportedFrameOnRequestStream(_incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame),
+                CoreStrings.FormatHttp3ErrorUnsupportedFrameOnRequestStream(incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame),
             // The server should never receive push promise
             Http3FrameType.PushPromise => throw new Http3ConnectionErrorException(
-                CoreStrings.FormatHttp3ErrorUnsupportedFrameOnServer(_incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame),
+                CoreStrings.FormatHttp3ErrorUnsupportedFrameOnServer(incomingFrame.FormattedType), Http3ErrorCode.UnexpectedFrame),
             _ => ProcessUnknownFrameAsync(),
         };
     }
@@ -773,11 +782,13 @@ private static Task ProcessUnknownFrameAsync()
         return Task.CompletedTask;
     }
 
-    private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext> application, ReadOnlySequence<byte> payload, bool isCompleted) where TContext : notnull
+    private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext> application, Http3RawFrame incomingFrame, bool isContinuedFrame,
+        ReadOnlySequence<byte> payload, bool isCompleted) where TContext : notnull
     {
         // HEADERS frame after trailing headers is invalid.
         // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-4.1
-        if (_requestHeaderParsingState == RequestHeaderParsingState.Trailers)
+        // Since we parse data as we get it, we can receive partial frames which means we need to check that we're in the middle of handling the trailers header frame
+        if (_requestHeaderParsingState == RequestHeaderParsingState.Trailers && !isContinuedFrame)
         {
             throw new Http3ConnectionErrorException(CoreStrings.FormatHttp3StreamErrorFrameReceivedAfterTrailers(Http3Formatting.ToFormattedType(Http3FrameType.Headers)), Http3ErrorCode.UnexpectedFrame);
         }
@@ -789,8 +800,17 @@ private async Task ProcessHeadersFrameAsync<TContext>(IHttpApplication<TContext>
 
         try
         {
-            QPackDecoder.Decode(payload, endHeaders: true, handler: this);
-            QPackDecoder.Reset();
+            var endHeaders = payload.Length == incomingFrame.RemainingLength;
+            QPackDecoder.Decode(payload, endHeaders, handler: this);
+            if (endHeaders)
+            {
+                QPackDecoder.Reset();
+            }
+            else
+            {
+                // Headers frame isn't complete, return to read more of the frame
+                return;
+            }
         }
         catch (QPackDecodingException ex)
         {
diff --git a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http3.cs b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http3.cs
index 4159c927e531..54e32f258f00 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http3.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http3.cs
@@ -37,7 +37,7 @@ public void Http3FrameReceived(string connectionId, long streamId, Http3RawFrame
     {
         if (_http3Logger.IsEnabled(LogLevel.Trace))
         {
-            Http3Log.Http3FrameReceived(_http3Logger, connectionId, Http3Formatting.ToFormattedType(frame.Type), streamId, frame.Length);
+            Http3Log.Http3FrameReceived(_http3Logger, connectionId, Http3Formatting.ToFormattedType(frame.Type), streamId, frame.RemainingLength);
         }
     }
 
@@ -45,7 +45,7 @@ public void Http3FrameSending(string connectionId, long streamId, Http3RawFrame
     {
         if (_http3Logger.IsEnabled(LogLevel.Trace))
         {
-            Http3Log.Http3FrameSending(_http3Logger, connectionId, Http3Formatting.ToFormattedType(frame.Type), streamId, frame.Length);
+            Http3Log.Http3FrameSending(_http3Logger, connectionId, Http3Formatting.ToFormattedType(frame.Type), streamId, frame.RemainingLength);
         }
     }
 
diff --git a/src/Servers/Kestrel/Core/test/VariableIntHelperTests.cs b/src/Servers/Kestrel/Core/test/VariableIntHelperTests.cs
index 8b73bd0e2c48..f8fa53170829 100644
--- a/src/Servers/Kestrel/Core/test/VariableIntHelperTests.cs
+++ b/src/Servers/Kestrel/Core/test/VariableIntHelperTests.cs
@@ -14,7 +14,8 @@ public class VariableIntHelperTests
     [MemberData(nameof(IntegerData))]
     public void CheckDecoding(long expected, byte[] input)
     {
-        var decoded = VariableLengthIntegerHelper.GetInteger(new ReadOnlySequence<byte>(input), out _, out _);
+        var result = VariableLengthIntegerHelper.TryGetInteger(new ReadOnlySequence<byte>(input), out _, out var decoded);
+        Assert.True(result);
         Assert.Equal(expected, decoded);
     }
 
diff --git a/src/Servers/Kestrel/shared/test/Http3/Http3InMemory.cs b/src/Servers/Kestrel/shared/test/Http3/Http3InMemory.cs
index e02573b7b225..544b338ee38f 100644
--- a/src/Servers/Kestrel/shared/test/Http3/Http3InMemory.cs
+++ b/src/Servers/Kestrel/shared/test/Http3/Http3InMemory.cs
@@ -388,15 +388,15 @@ private static long GetOutputResponseBufferSize(ServiceContext serviceContext)
         return bufferSize ?? 0;
     }
 
-    internal ValueTask<Http3ControlStream> CreateControlStream()
+    internal ValueTask<Http3ControlStream> CreateControlStream(PipeScheduler clientWriterScheduler = null)
     {
-        return CreateControlStream(id: 0);
+        return CreateControlStream(id: 0, clientWriterScheduler);
     }
 
-    internal async ValueTask<Http3ControlStream> CreateControlStream(int? id)
+    internal async ValueTask<Http3ControlStream> CreateControlStream(int? id, PipeScheduler clientWriterScheduler = null)
     {
         var testStreamContext = new TestStreamContext(canRead: true, canWrite: false, this);
-        testStreamContext.Initialize(streamId: 2);
+        testStreamContext.Initialize(streamId: 2, clientWriterScheduler);
 
         var stream = new Http3ControlStream(this, testStreamContext);
         _runningStreams[stream.StreamId] = stream;
@@ -409,16 +409,17 @@ internal async ValueTask<Http3ControlStream> CreateControlStream(int? id)
         return stream;
     }
 
-    internal async ValueTask<Http3RequestStream> CreateRequestStream(IEnumerable<KeyValuePair<string, string>> headers, Http3RequestHeaderHandler headerHandler = null, bool endStream = false, TaskCompletionSource tsc = null)
+    internal async ValueTask<Http3RequestStream> CreateRequestStream(IEnumerable<KeyValuePair<string, string>> headers,
+        Http3RequestHeaderHandler headerHandler = null, bool endStream = false, TaskCompletionSource tsc = null, PipeScheduler clientWriterScheduler = null)
     {
-        var stream = CreateRequestStreamCore(headerHandler);
+        var stream = CreateRequestStreamCore(headerHandler, clientWriterScheduler);
 
         if (tsc is not null)
         {
             stream.StartStreamDisposeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
         }
 
-        if (headers is not null)
+        if (headers is not null && headers.Any())
         {
             await stream.SendHeadersAsync(headers, endStream);
         }
@@ -430,9 +431,10 @@ internal async ValueTask<Http3RequestStream> CreateRequestStream(IEnumerable<Key
         return stream;
     }
 
-    internal async ValueTask<Http3RequestStream> CreateRequestStream(Http3HeadersEnumerator headers, Http3RequestHeaderHandler headerHandler = null, bool endStream = false, TaskCompletionSource tsc = null)
+    internal async ValueTask<Http3RequestStream> CreateRequestStream(Http3HeadersEnumerator headers, Http3RequestHeaderHandler headerHandler = null,
+        bool endStream = false, TaskCompletionSource tsc = null, PipeScheduler clientWriterScheduler = null)
     {
-        var stream = CreateRequestStreamCore(headerHandler);
+        var stream = CreateRequestStreamCore(headerHandler, clientWriterScheduler);
 
         if (tsc is not null)
         {
@@ -448,7 +450,7 @@ internal async ValueTask<Http3RequestStream> CreateRequestStream(Http3HeadersEnu
         return stream;
     }
 
-    private Http3RequestStream CreateRequestStreamCore(Http3RequestHeaderHandler headerHandler)
+    private Http3RequestStream CreateRequestStreamCore(Http3RequestHeaderHandler headerHandler, PipeScheduler clientWriterScheduler)
     {
         var requestStreamId = GetStreamId(0x00);
         if (!_streamContextPool.TryDequeue(out var testStreamContext))
@@ -459,7 +461,7 @@ private Http3RequestStream CreateRequestStreamCore(Http3RequestHeaderHandler hea
         {
             Logger.LogDebug($"Reusing context for request stream {requestStreamId}.");
         }
-        testStreamContext.Initialize(requestStreamId);
+        testStreamContext.Initialize(requestStreamId, clientWriterScheduler);
 
         return new Http3RequestStream(this, Connection, testStreamContext, headerHandler ?? new Http3RequestHeaderHandler());
     }
@@ -559,7 +561,7 @@ internal async ValueTask<Http3FrameWithPayload> ReceiveFrameAsync(bool expectEnd
                     throw new InvalidOperationException("No data received.");
                 }
 
-                if (Http3FrameReader.TryReadFrame(ref buffer, frame, out var framePayload))
+                if (Http3FrameReader.TryReadFrame(ref buffer, frame, isContinuedFrame: false, out var framePayload))
                 {
                     consumed = examined = framePayload.End;
                     frame.Payload = framePayload.ToArray();
@@ -837,16 +839,14 @@ internal async ValueTask<Dictionary<long, long>> ExpectSettingsAsync()
         var settings = new Dictionary<long, long>();
         while (true)
         {
-            var id = VariableLengthIntegerHelper.GetInteger(payload, out var consumed, out _);
-            if (id == -1)
+            if (!VariableLengthIntegerHelper.TryGetInteger(payload, out var consumed, out var id))
             {
                 break;
             }
 
             payload = payload.Slice(consumed);
 
-            var value = VariableLengthIntegerHelper.GetInteger(payload, out consumed, out _);
-            if (value == -1)
+            if (!VariableLengthIntegerHelper.TryGetInteger(payload, out consumed, out var value))
             {
                 break;
             }
@@ -927,9 +927,9 @@ public async ValueTask<long> TryReadStreamIdAsync()
             {
                 if (!readableBuffer.IsEmpty)
                 {
-                    var id = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out examined);
-                    if (id != -1)
+                    if (VariableLengthIntegerHelper.TryGetInteger(readableBuffer, out consumed, out var id))
                     {
+                        examined = consumed;
                         return id;
                     }
                 }
@@ -1005,6 +1005,7 @@ public TestMultiplexedConnectionContext(Http3InMemory testBase)
         Features.Set<IProtocolErrorCodeFeature>(this);
         Features.Set<IConnectionMetricsContextFeature>(this);
         ConnectionClosedRequested = ConnectionClosingCts.Token;
+        ConnectionClosed = ConnectionClosedCts.Token;
     }
 
     public override string ConnectionId { get; set; }
@@ -1017,6 +1018,8 @@ public TestMultiplexedConnectionContext(Http3InMemory testBase)
 
     public CancellationTokenSource ConnectionClosingCts { get; set; } = new CancellationTokenSource();
 
+    public CancellationTokenSource ConnectionClosedCts { get; set; } = new CancellationTokenSource();
+
     public long Error
     {
         get => _error ?? -1;
@@ -1033,6 +1036,7 @@ public override void Abort(ConnectionAbortedException abortReason)
     {
         ToServerAcceptQueue.Writer.TryComplete();
         ToClientAcceptQueue.Writer.TryComplete();
+        ConnectionClosedCts.Cancel();
     }
 
     public override async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default)
@@ -1106,38 +1110,30 @@ public TestStreamContext(bool canRead, bool canWrite, Http3InMemory testBase)
         _testBase = testBase;
     }
 
-    public void Initialize(long streamId)
+    public void Initialize(long streamId, PipeScheduler clientWriterScheduler = null)
     {
-        if (!_isComplete)
-        {
-            // Create new pipes when test stream context is reused rather than reseting them.
-            // This is required because the client tests read from these directly from these pipes.
-            // When a request is finished they'll check to see whether there is anymore content
-            // in the Application.Output pipe. If it has been reset then that code will error.
-            var inputOptions = Http3InMemory.GetInputPipeOptions(_testBase._serviceContext, _testBase._memoryPool, PipeScheduler.ThreadPool);
-            var outputOptions = Http3InMemory.GetOutputPipeOptions(_testBase._serviceContext, _testBase._memoryPool, PipeScheduler.ThreadPool);
-
-            _inputPipe = new Pipe(inputOptions);
-            _outputPipe = new Pipe(outputOptions);
-
-            _transportPipeReader = new CompletionPipeReader(_inputPipe.Reader);
-            _transportPipeWriter = new CompletionPipeWriter(_outputPipe.Writer);
-
-            _pair = new DuplexPipePair(
-                new DuplexPipe(_transportPipeReader, _transportPipeWriter),
-                new DuplexPipe(_outputPipe.Reader, _inputPipe.Writer));
-        }
-        else
+        if (_isComplete)
         {
             _pair.Application.Input.Complete();
             _pair.Application.Output.Complete();
+        }
 
-            _transportPipeReader.Reset();
-            _transportPipeWriter.Reset();
+        // Create new pipes when test stream context is reused rather than reseting them.
+        // This is required because the client tests read from these directly from these pipes.
+        // When a request is finished they'll check to see whether there is anymore content
+        // in the Application.Output pipe. If it has been reset then that code will error.
+        var inputOptions = Http3InMemory.GetInputPipeOptions(_testBase._serviceContext, _testBase._memoryPool, clientWriterScheduler ?? PipeScheduler.ThreadPool);
+        var outputOptions = Http3InMemory.GetOutputPipeOptions(_testBase._serviceContext, _testBase._memoryPool, PipeScheduler.ThreadPool);
 
-            _inputPipe.Reset();
-            _outputPipe.Reset();
-        }
+        _inputPipe = new Pipe(inputOptions);
+        _outputPipe = new Pipe(outputOptions);
+
+        _transportPipeReader = new CompletionPipeReader(_inputPipe.Reader);
+        _transportPipeWriter = new CompletionPipeWriter(_outputPipe.Writer);
+
+        _pair = new DuplexPipePair(
+            new DuplexPipe(_transportPipeReader, _transportPipeWriter),
+            new DuplexPipe(_outputPipe.Reader, _inputPipe.Writer));
 
         Features.Set<IStreamDirectionFeature>(this);
         Features.Set<IStreamIdFeature>(this);
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3ConnectionTests.cs
index b1ff24b43bf8..054577365d7d 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3ConnectionTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3ConnectionTests.cs
@@ -354,6 +354,34 @@ await Http3Api.WaitForConnectionErrorAsync<Http3ConnectionErrorException>(
             expectedErrorMessage: CoreStrings.Http3ErrorControlStreamClosed);
     }
 
+    [Theory]
+    [InlineData((int)Http3FrameType.Settings, 20_000)]
+    //[InlineData((int)Http3FrameType.GoAway, 30)] // GoAway frames trigger graceful connection close which races with sending FRAME_ERROR
+    [InlineData((int)Http3FrameType.CancelPush, 30)]
+    [InlineData((int)Http3FrameType.MaxPushId, 30)]
+    [InlineData(int.MaxValue, 20_000)] // Unknown frame type
+    public async Task ControlStream_ClientToServer_LargeFrame_ConnectionError(int frameType, int length)
+    {
+        await Http3Api.InitializeConnectionAsync(_noopApplication);
+
+        var controlStream = await Http3Api.CreateControlStream();
+
+        // Need to send settings frame before other frames, otherwise it's a connection error
+        if (frameType != (int)Http3FrameType.Settings)
+        {
+            await controlStream.SendSettingsAsync(new List<Http3PeerSetting>());
+        }
+
+        await controlStream.SendFrameAsync((Http3FrameType)frameType, new byte[length]);
+
+        await Http3Api.WaitForConnectionErrorAsync<Http3ConnectionErrorException>(
+            ignoreNonGoAwayFrames: true,
+            expectedLastStreamId: 0,
+            expectedErrorCode: Http3ErrorCode.FrameError,
+            matchExpectedErrorMessage: AssertExpectedErrorMessages,
+            expectedErrorMessage: CoreStrings.FormatHttp3ControlStreamFrameTooLarge(Http3Formatting.ToFormattedType((Http3FrameType)frameType)));
+    }
+
     [Fact]
     public async Task SETTINGS_MaxFieldSectionSizeSent_ServerReceivesValue()
     {
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3StreamTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3StreamTests.cs
index 728bc3458b74..c23e11328e43 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3StreamTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http3/Http3StreamTests.cs
@@ -1,11 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System;
-using System.Collections.Generic;
+using System.Buffers;
 using System.Globalization;
-using System.IO;
-using System.Linq;
+using System.IO.Pipelines;
 using System.Net.Http;
 using System.Runtime.ExceptionServices;
 using System.Text;
@@ -17,6 +15,7 @@
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3;
 using Microsoft.AspNetCore.Testing;
 using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Primitives;
 using Microsoft.Net.Http.Headers;
 using Xunit;
 
@@ -1982,7 +1981,7 @@ public async Task RequestTrailers_CanReadTrailersFromRequest()
         var trailers = new[]
         {
                 new KeyValuePair<string, string>("TestName", "TestValue"),
-            };
+        };
         var requestStream = await Http3Api.InitializeConnectionAndStreamsAsync(async c =>
         {
             await c.Request.Body.DrainAsync(default);
@@ -2360,6 +2359,21 @@ public Task HEADERS_Received_HeaderBlockOverLimitx2_ConnectionError()
         return HEADERS_Received_InvalidHeaderFields_StreamError(headers, CoreStrings.BadRequest_HeadersExceedMaxTotalSize, Http3ErrorCode.RequestRejected);
     }
 
+    [Fact]
+    public Task HEADERS_Received_HeaderValueOverLimit_ConnectionError()
+    {
+        var limit = _serviceContext.ServerOptions.Limits.Http3.MaxRequestHeaderFieldSize;
+        // Single header value exceeds limit
+        var headers = new[]
+        {
+            new KeyValuePair<string, string>("a", new string('a', limit + 1)),
+        };
+
+        return HEADERS_Received_InvalidHeaderFields_StreamError(headers,
+            SR.Format(SR.net_http_headers_exceeded_length, limit),
+            Http3ErrorCode.InternalError);
+    }
+
     [Fact]
     public async Task HEADERS_Received_TooManyHeaders_431()
     {
@@ -2976,4 +2990,296 @@ public async Task GetMemory_AfterAbort_GetsFakeMemory(int sizeHint)
             context.Response.BodyWriter.Advance(memory.Length);
         }, headers);
     }
+
+    [Fact]
+    public async Task ControlStream_CloseBeforeSendingSettings()
+    {
+        await Http3Api.InitializeConnectionAsync(_noopApplication);
+
+        var outboundcontrolStream = await Http3Api.CreateControlStream();
+
+        await outboundcontrolStream.EndStreamAsync();
+
+        await outboundcontrolStream.ReceiveEndAsync();
+    }
+
+    [Fact]
+    public async Task ControlStream_PartialFrameThenClose()
+    {
+        await Http3Api.InitializeConnectionAsync(_noopApplication);
+
+        var outboundcontrolStream = await Http3Api.CreateControlStream();
+
+        var settings = new List<Http3PeerSetting>
+        {
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.MaxFieldSectionSize, 100),
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.EnableWebTransport, 1),
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.H3Datagram, 1)
+        };
+        var len = Http3FrameWriter.CalculateSettingsSize(settings);
+
+        Http3FrameWriter.WriteHeader(Http3FrameType.Settings, len, outboundcontrolStream.Pair.Application.Output);
+
+        var parameterLength = VariableLengthIntegerHelper.WriteInteger(outboundcontrolStream.Pair.Application.Output.GetSpan(), (long)Internal.Http3.Http3SettingType.MaxFieldSectionSize);
+        outboundcontrolStream.Pair.Application.Output.Advance(parameterLength);
+        await outboundcontrolStream.Pair.Application.Output.FlushAsync();
+
+        await outboundcontrolStream.EndStreamAsync();
+
+        await outboundcontrolStream.ReceiveEndAsync();
+    }
+
+    [Fact]
+    public async Task SendDataObservesBackpressureFromApp()
+    {
+        var headers = new[]
+        {
+            new KeyValuePair<string, string>(InternalHeaderNames.Method, "Custom"),
+            new KeyValuePair<string, string>(InternalHeaderNames.Path, "/"),
+            new KeyValuePair<string, string>(InternalHeaderNames.Scheme, "http"),
+            new KeyValuePair<string, string>(InternalHeaderNames.Authority, "localhost:80"),
+        };
+
+        // Http3Stream hardcodes a 64k size for the RequestBodyPipe there is also the transport Pipe which we can influence with MaxRequestBufferSize
+        // So we need to send enough to fill up the 64k Pipe as well as the 100 byte Pipe.
+        var sendSize = 1024 * 65;
+        _serviceContext.ServerOptions.Limits.MaxRequestBufferSize = 100;
+        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+        var startedReadingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+        var requestStream = await Http3Api.InitializeConnectionAndStreamsAsync(async c =>
+        {
+            // Read a single byte to make sure data has gotten here before we start verifying backpressure in the test code
+            var res = await c.Request.BodyReader.ReadAsync();
+            Assert.Equal(sendSize, res.Buffer.Length);
+            c.Request.BodyReader.AdvanceTo(res.Buffer.Slice(1).Start);
+            startedReadingTcs.SetResult();
+
+            await tcs.Task;
+            res = await c.Request.BodyReader.ReadAsync();
+            Assert.Equal(sendSize - 1, res.Buffer.Length);
+            c.Request.BodyReader.AdvanceTo(res.Buffer.End);
+        }, headers);
+
+        var sendTask = requestStream.SendDataAsync(Encoding.ASCII.GetBytes(new string('a', sendSize)));
+
+        // Wait for "app" code to start reading to ensure it has gotten bytes before we start verifying backpressure
+        await startedReadingTcs.Task;
+        Assert.False(sendTask.IsCompleted);
+        tcs.SetResult();
+
+        await sendTask;
+
+        var responseHeaders = await requestStream.ExpectHeadersAsync();
+        Assert.Equal("200", responseHeaders[InternalHeaderNames.Status]);
+
+        await requestStream.ExpectReceiveEndOfStream();
+    }
+
+    [Fact]
+    public async Task Request_FrameParsingSingleByteAtATimeWorks()
+    {
+        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+        var total = 0;
+        var trailerValue = string.Empty;
+        await Http3Api.InitializeConnectionAsync(async context =>
+        {
+            var buffer = new byte[100];
+            var read = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length);
+            var captureTcs = tcs;
+            tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+            captureTcs.SetResult();
+            Assert.Equal(1, read);
+            total = read;
+            while (read > 0)
+            {
+                read = await context.Request.Body.ReadAsync(buffer, total, buffer.Length - total);
+                captureTcs = tcs;
+                tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+                captureTcs.SetResult();
+                total += read;
+                if (read == 0)
+                {
+                    break;
+                }
+                Assert.Equal(1, read);
+            }
+
+            trailerValue = context.Request.GetTrailer("TestName");
+        });
+
+        // Use Inline scheduling and buffer size of 1 to guarantee each write will wait for the parsing loop to complete before writing more data
+        _serviceContext.ServerOptions.Limits.MaxRequestBufferSize = 1;
+        var stream = await Http3Api.CreateRequestStream(headers: [], clientWriterScheduler: PipeScheduler.Inline);
+
+        // Use local pipe to write frames so we can get the entire buffer in order to write it one byte at a time
+        var bufferPipe = new Pipe();
+        Http3FrameWriter.WriteHeader(Http3FrameType.Headers, frameLength: 38, bufferPipe.Writer);
+
+        var headersTotalSize = 0;
+        var headers = new Http3HeadersEnumerator();
+        headers.Initialize(new Dictionary<string, StringValues>() {
+            { InternalHeaderNames.Method, "POST" },
+            { InternalHeaderNames.Path, "/" },
+            { InternalHeaderNames.Scheme, "http" }, });
+
+        var mem = bufferPipe.Writer.GetMemory();
+        var done = QPackHeaderWriter.BeginEncodeHeaders(headers, mem.Span, ref headersTotalSize, out var length);
+        Assert.True(done);
+        bufferPipe.Writer.Advance(length);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write header frame one byte at a time
+        await WriteOneByteAtATime(bufferPipe.Reader, stream.Pair.Application.Output);
+
+        Http3FrameWriter.WriteHeader(Http3FrameType.Data, frameLength: 12, bufferPipe.Writer);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write data header one byte at a time
+        await WriteOneByteAtATime(bufferPipe.Reader, stream.Pair.Application.Output);
+
+        bufferPipe.Writer.Write(new byte[12]);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write data in data frame one byte at a time
+        // Don't use WriteOneByteAtATime() as we want to wait on the TCS after every flush to make sure app code consumed the data
+        // before we send another byte
+        var res = await bufferPipe.Reader.ReadAsync();
+        for (var i = 0; i < res.Buffer.Length; i++)
+        {
+            mem = stream.Pair.Application.Output.GetMemory();
+            mem.Span[0] = res.Buffer.Slice(i).FirstSpan[0];
+            stream.Pair.Application.Output.Advance(1);
+            // Use TCS to make sure app can read data before we send more
+            var capturedTcs = tcs;
+            await stream.Pair.Application.Output.FlushAsync();
+            await capturedTcs.Task;
+        }
+        bufferPipe.Reader.AdvanceTo(res.Buffer.End);
+
+        var trailers = new Http3HeadersEnumerator();
+        trailers.Initialize(new Dictionary<string, StringValues>()
+        {
+            { "TestName", "TestValue" }
+        });
+
+        Http3FrameWriter.WriteHeader(Http3FrameType.Headers, frameLength: 22, bufferPipe.Writer);
+        mem = bufferPipe.Writer.GetMemory();
+        done = QPackHeaderWriter.BeginEncodeHeaders(trailers, mem.Span, ref headersTotalSize, out length);
+        Assert.True(done);
+        bufferPipe.Writer.Advance(length);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write trailer frame one byte at a time
+        await WriteOneByteAtATime(bufferPipe.Reader, stream.Pair.Application.Output);
+
+        await stream.EndStreamAsync();
+
+        var responseHeaders = await stream.ExpectHeadersAsync();
+        Assert.Equal(3, responseHeaders.Count);
+        Assert.Contains("date", responseHeaders.Keys, StringComparer.OrdinalIgnoreCase);
+        Assert.Equal("200", responseHeaders[InternalHeaderNames.Status]);
+        Assert.Equal("0", responseHeaders["content-length"]);
+
+        await stream.ExpectReceiveEndOfStream();
+
+        Assert.Equal(12, total);
+        Assert.Equal("TestValue", trailerValue);
+    }
+
+    [Fact]
+    public async Task Control_FrameParsingSingleByteAtATimeWorks()
+    {
+        await Http3Api.InitializeConnectionAsync(_noopApplication);
+
+        // Use Inline scheduling and buffer size of 1 to guarantee each write will wait for the parsing loop to complete before writing more data
+        _serviceContext.ServerOptions.Limits.MaxRequestBufferSize = 1;
+        var outboundcontrolStream = await Http3Api.CreateControlStream(clientWriterScheduler: PipeScheduler.Inline);
+
+        // Use local pipe to write frames so we can get the entire buffer in order to write it one byte at a time
+        var bufferPipe = new Pipe();
+
+        var settings = new List<Http3PeerSetting>
+        {
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.MaxFieldSectionSize, 100),
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.EnableWebTransport, 1),
+            new Http3PeerSetting(Internal.Http3.Http3SettingType.H3Datagram, 1)
+        };
+        var len = Http3FrameWriter.CalculateSettingsSize(settings);
+
+        Http3FrameWriter.WriteHeader(Http3FrameType.Settings, len, bufferPipe.Writer);
+        var mem = bufferPipe.Writer.GetMemory();
+        Http3FrameWriter.WriteSettings(settings, mem.Span);
+
+        bufferPipe.Writer.Advance(len);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write Settings frame one byte at a time
+        await WriteOneByteAtATime(bufferPipe.Reader, outboundcontrolStream.Pair.Application.Output);
+
+        var fieldSetting = await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();
+
+        Assert.Equal(Internal.Http3.Http3SettingType.MaxFieldSectionSize, fieldSetting.Key);
+        Assert.Equal(100, fieldSetting.Value);
+
+        fieldSetting = await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();
+        Assert.Equal(Internal.Http3.Http3SettingType.EnableWebTransport, fieldSetting.Key);
+        Assert.Equal(1, fieldSetting.Value);
+
+        fieldSetting = await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();
+        Assert.Equal(Internal.Http3.Http3SettingType.H3Datagram, fieldSetting.Key);
+        Assert.Equal(1, fieldSetting.Value);
+
+        // Frames must be well-formed otherwise we close the connection with a frame error
+        Http3FrameWriter.WriteHeader(Http3FrameType.CancelPush, frameLength: 2, bufferPipe.Writer);
+        var idLength = VariableLengthIntegerHelper.WriteInteger(bufferPipe.Writer.GetSpan(), longToEncode: 1026);
+        bufferPipe.Writer.Advance(idLength);
+        await bufferPipe.Writer.FlushAsync();
+
+        // Write CancelPush frame one byte at a time
+        await WriteOneByteAtATime(bufferPipe.Reader, outboundcontrolStream.Pair.Application.Output);
+
+        // Frames must be well-formed otherwise we close the connection with a frame error
+        Http3FrameWriter.WriteHeader(Http3FrameType.GoAway, frameLength: 4, bufferPipe.Writer);
+        idLength = VariableLengthIntegerHelper.WriteInteger(bufferPipe.Writer.GetSpan(), longToEncode: 100026);
+        bufferPipe.Writer.Advance(idLength);
+        await bufferPipe.Writer.FlushAsync();
+
+        try
+        {
+            // Write GoAway frame one byte at a time
+            await WriteOneByteAtATime(bufferPipe.Reader, outboundcontrolStream.Pair.Application.Output);
+        }
+        // As soon as the GOAWAY frame identifier is processed we initiate the connection close process.
+        // That means it's possible to still be writing to the stream when we close the
+        // connection which would result in an exception. We'll just ignore the exception in this case.
+        catch (Exception) { }
+
+        await outboundcontrolStream.EndStreamAsync();
+
+        // Check that connection is closed.
+        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+        Http3Api.MultiplexedConnectionContext.ConnectionClosed.Register(() => tcs.TrySetResult());
+        await tcs.Task;
+
+        await outboundcontrolStream.ReceiveEndAsync();
+    }
+
+    private async Task WriteOneByteAtATime(PipeReader reader, PipeWriter writer)
+    {
+        var res = await reader.ReadAsync();
+        try
+        {
+            for (var i = 0; i < res.Buffer.Length; i++)
+            {
+                var mem = writer.GetMemory();
+                mem.Span[0] = res.Buffer.Slice(i).FirstSpan[0];
+                writer.Advance(1);
+                await writer.FlushAsync();
+            }
+        }
+        finally
+        {
+            reader.AdvanceTo(res.Buffer.End);
+        }
+    }
 }
diff --git a/src/Shared/runtime/Http3/Helpers/VariableLengthIntegerHelper.cs b/src/Shared/runtime/Http3/Helpers/VariableLengthIntegerHelper.cs
index 3a343a62a4cc..c7f1ec908d0f 100644
--- a/src/Shared/runtime/Http3/Helpers/VariableLengthIntegerHelper.cs
+++ b/src/Shared/runtime/Http3/Helpers/VariableLengthIntegerHelper.cs
@@ -128,19 +128,19 @@ static bool TryReadSlow(ref SequenceReader<byte> reader, out long value)
             }
         }
 
-        public static long GetInteger(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+        // If callsite has 'examined', set it to buffer.End if the integer wasn't successfully read, otherwise set examined = consumed.
+        public static bool TryGetInteger(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out long integer)
         {
             var reader = new SequenceReader<byte>(buffer);
-            if (TryRead(ref reader, out long value))
+            if (TryRead(ref reader, out integer))
             {
-                consumed = examined = buffer.GetPosition(reader.Consumed);
-                return value;
+                consumed = buffer.GetPosition(reader.Consumed);
+                return true;
             }
             else
             {
-                consumed = default;
-                examined = buffer.End;
-                return -1;
+                consumed = buffer.Start;
+                return false;
             }
         }
 
diff --git a/src/Shared/test/Shared.Tests/runtime/Http3/VariableLengthIntegerHelperTests.cs b/src/Shared/test/Shared.Tests/runtime/Http3/VariableLengthIntegerHelperTests.cs
index d67d24c0ba25..e461bfd41ed4 100644
--- a/src/Shared/test/Shared.Tests/runtime/Http3/VariableLengthIntegerHelperTests.cs
+++ b/src/Shared/test/Shared.Tests/runtime/Http3/VariableLengthIntegerHelperTests.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
@@ -223,12 +223,12 @@ public void GetInteger_ValidSegmentedSequence()
             MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 0, 2 });
             ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                 memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
-            long result = VariableLengthIntegerHelper.GetInteger(readOnlySequence,
-                out SequencePosition consumed, out SequencePosition examined);
+            bool result = VariableLengthIntegerHelper.TryGetInteger(readOnlySequence,
+                out SequencePosition consumed, out long integer);
 
-            Assert.Equal(2, result);
+            Assert.True(result);
+            Assert.Equal(2, integer);
             Assert.Equal(7, consumed.GetInteger());
-            Assert.Equal(7, examined.GetInteger());
         }
 
         [Fact]
@@ -238,12 +238,11 @@ public void GetInteger_NotValidSegmentedSequence()
             MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 2 });
             ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                 memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
-            long result = VariableLengthIntegerHelper.GetInteger(readOnlySequence,
-                out SequencePosition consumed, out SequencePosition examined);
+            bool result = VariableLengthIntegerHelper.TryGetInteger(readOnlySequence,
+                out SequencePosition consumed, out long integer);
 
-            Assert.Equal(-1, result);
+            Assert.False(result);
             Assert.Equal(0, consumed.GetInteger());
-            Assert.Equal(6, examined.GetInteger());
         }
 
         [Fact]
diff --git a/src/SignalR/clients/ts/FunctionalTests/Startup.cs b/src/SignalR/clients/ts/FunctionalTests/Startup.cs
index 45d3f8546a71..dd3ee9378458 100644
--- a/src/SignalR/clients/ts/FunctionalTests/Startup.cs
+++ b/src/SignalR/clients/ts/FunctionalTests/Startup.cs
@@ -184,9 +184,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<
                 {
                     cookieOptions.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
                     cookieOptions.Secure = true;
+                    cookieOptions.Extensions.Add("partitioned"); // Required by Chromium
 
                     expiredCookieOptions.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
                     expiredCookieOptions.Secure = true;
+                    expiredCookieOptions.Extensions.Add("partitioned"); // Required by Chromium
                 }
                 context.Response.Cookies.Append("testCookie", "testValue", cookieOptions);
                 context.Response.Cookies.Append("testCookie2", "testValue2", cookieOptions);
diff --git a/src/submodules/googletest b/src/submodules/googletest
index e235eb34c6c4..24a9e940d481 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit e235eb34c6c4fed790ccdad4b16394301360dcd4
+Subproject commit 24a9e940d481f992ba852599c78bb2217362847b