Skip to content

[AppSec] APPSEC-65483 Collect Datadog security-testing headers on entry spans#8682

Merged
christophe-papazian merged 11 commits into
masterfrom
christophe.papazian/appsec-65483-security-testing-headers
May 27, 2026
Merged

[AppSec] APPSEC-65483 Collect Datadog security-testing headers on entry spans#8682
christophe-papazian merged 11 commits into
masterfrom
christophe.papazian/appsec-65483-security-testing-headers

Conversation

@christophe-papazian

Copy link
Copy Markdown
Collaborator

Summary of changes

Tag x-datadog-endpoint-scan and x-datadog-security-test HTTP request headers as http.request.headers.<name> on every HTTP server entry span (and the inferred-proxy span when one is created), unconditionally — independent of DD_TRACE_HEADER_TAGS and AppSec enablement. Markers are not propagated downstream.

Reason for change

APPSEC-65483 — RFC "Security Testing: Trace Attribution for Inventory Enrichment and Pollution Prevention". These two markers let the API endpoint reducer distinguish Datadog scan/test traffic from real user traffic and keep it out of the API inventory.

Sibling-tracer implementations already merged: dd-trace-py#18049, dd-trace-js#8463, dd-trace-java#11418.

Implementation details

  • New SpanContextPropagator.AddSecurityTestingHeadersAsTags<THeaders> reads both markers from any IHeadersCollection and tags them on the supplied span. Tag names are precomputed; string[] fast-path avoids enumerator allocation on the legacy NameValueCollection / WebHeaderCollection carriers; presence-based (empty values still tagged).
  • Wired into every HTTP server entry path:
    • AspNetMvcIntegration (System.Web MVC) — entry span + inferred-proxy span (proxy tagged at creation site)
    • AspNetWebApi2Integration (System.Web Web API 2) — entry span (no proxy support on this path)
    • TracingHttpModule (OWIN/IIS classic) — entry span + inferred-proxy span
    • AspNetCoreHttpRequestHandler (ASP.NET Core, including Azure Functions isolated worker HTTP-proxying mode) — entry span + inferred-proxy span
    • WcfCommon (WCF over HTTP) — entry span

Test coverage

  • SpanContextPropagatorTests_AddSecurityTestingHeadersAsTags (new — 13 cases): both markers + unrelated header, absent headers, no HeaderTags config, only one marker present, empty-string value still tagged, case-insensitive lookup, ASP.NET Core HeadersCollectionAdapter with mixed-case lookup.
  • All existing SpanContextPropagatorTests* continue to pass.

Other details

APPSEC-65483

Tag `x-datadog-endpoint-scan` and `x-datadog-security-test` HTTP request
headers as `http.request.headers.<name>` on every HTTP server entry span
(and on the inferred-proxy span when one is created), unconditionally —
independent of `DD_TRACE_HEADER_TAGS` and AppSec enablement.

These markers let the API endpoint reducer distinguish Datadog scan/test
traffic from real user traffic and keep it out of the API inventory.

Wired into: ASP.NET MVC, ASP.NET Web API 2, OWIN/IIS classic, ASP.NET
Core, WCF over HTTP. Markers are not propagated downstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@christophe-papazian christophe-papazian requested review from a team as code owners May 22, 2026 15:39
@christophe-papazian christophe-papazian marked this pull request as draft May 22, 2026 15:40
@datadog-datadog-prod-us1

This comment has been minimized.

@christophe-papazian christophe-papazian added area:asm type:enhancement Improvement to an existing feature labels May 22, 2026
Comment thread tracer/src/Datadog.Trace/Propagators/SpanContextPropagator.cs
christophe-papazian and others added 2 commits May 26, 2026 11:23
System.ValueTuple<> is not in the net461 BCL, so the
`(string Header, string Tag)[]` precomputed-tags array broke
the Windows build. Switch to a small private struct matching
the existing `Key` struct pattern in the same file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@andrewlock andrewlock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, I wonder if we could/should get rid of all the looping given it's only 2 headers, but not required

Comment thread tracer/src/Datadog.Trace/AspNet/TracingHttpModule.cs
Comment thread tracer/src/Datadog.Trace/Propagators/SpanContextPropagator.cs Outdated
Per @andrewlock's review on #8682: inline both header lookups
directly in AddSecurityTestingHeadersAsTags instead of iterating
a precomputed (name, tag) array. Header / tag names become
compile-time string constants, the SecurityTestingHeader struct
and the static array are removed.

Each call site uses a single `is IList<string> { Count: > 0 }`
pattern match — covers every in-tree server carrier (string[],
boxed StringValues, BCL HttpHeaders.TryGetValues materialization)
without per-request enumerator allocation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@christophe-papazian

Copy link
Copy Markdown
Collaborator Author

Replying to @andrewlock's two open threads here so they're easy to find:

Inlining suggestion (SpanContextPropagator.cs): Applied in 2d75d30 — collapsed to two is IList<string> { Count: > 0 } blocks. Tried for the literal headers[name] form you sketched, but IHeadersCollection exposes GetValues returning IEnumerable<string> rather than an indexer. The IList<string> pattern catches every in-tree server carrier today (string[] for the legacy carriers, boxed StringValues for ASP.NET Core, and the BCL's HttpHeaders.TryGetValues materialization for the Web API 2 wrapper) without an enumerator allocation. It's a contract bet rather than a guarantee — a future non-IList IEnumerable<string> carrier would silently lose the markers. Calling it good for now; the cleanest principled fix would be tightening IHeadersCollection.GetValues to return IList<string> (or adding TryGetFirstValue), but that's bigger blast radius than this PR.

requestHeaders vs headers in TracingHttpModule.cs: going with headers — that's the NameValueHeadersCollection wrapper produced by requestHeaders.Wrap() a few lines above, which is what the IHeadersCollection-generic propagator API needs. requestHeaders is the raw NameValueCollection. Same value AddHeadersToSpanAsTags already takes one line up.

@pr-commenter

pr-commenter Bot commented May 26, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-05-26 19:17:47

Comparing candidate commit 53bda94 in PR branch christophe.papazian/appsec-65483-security-testing-headers with baseline commit fb43641 in branch master.

Found 0 performance improvements and 1 performance regressions! Performance is the same for 71 metrics, 0 unstable metrics, 59 known flaky benchmarks, 67 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:Benchmarks.Trace.HttpClientBenchmark.SendAsync net472

  • 🟥 throughput [-5677.631op/s; -5367.213op/s] or [-6.481%; -6.127%]

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472

  • 🟥 throughput [-5768.271op/s; -5293.875op/s] or [-6.839%; -6.277%]

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild netcoreapp3.1

  • 🟥 throughput [-6895.414op/s; -5551.736op/s] or [-7.011%; -5.645%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟥 execution_time [+301.447ms; +307.958ms] or [+149.589%; +152.820%]
  • 🟥 throughput [-45.592op/s; -42.000op/s] or [-8.203%; -7.557%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • 🟥 execution_time [+380.803ms; +383.033ms] or [+300.858%; +302.620%]
  • 🟩 throughput [+94.098op/s; +100.749op/s] or [+12.406%; +13.283%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+390.185ms; +392.201ms] or [+345.299%; +347.083%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net472

  • 🟥 allocated_mem [+1.308KB; +1.308KB] or [+27.528%; +27.540%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net6.0

  • 🟥 allocated_mem [+471 bytes; +472 bytes] or [+9.976%; +9.987%]
  • 🟩 execution_time [-16.065ms; -11.889ms] or [-7.503%; -5.553%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody netcoreapp3.1

  • 🟥 allocated_mem [+1.272KB; +1.272KB] or [+27.500%; +27.510%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net472

  • 🟥 allocated_mem [+1.307KB; +1.307KB] or [+105.743%; +105.758%]
  • 🟥 throughput [-260398.263op/s; -257420.823op/s] or [-26.588%; -26.284%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net6.0

  • 🟥 allocated_mem [+471 bytes; +472 bytes] or [+38.557%; +38.566%]
  • 🟩 execution_time [-26.452ms; -21.594ms] or [-11.796%; -9.630%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1

  • 🟥 allocated_mem [+1.272KB; +1.272KB] or [+105.288%; +105.304%]
  • 🟥 throughput [-157024.799op/s; -140857.889op/s] or [-22.561%; -20.239%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net6.0

  • 🟩 throughput [+8783.106op/s; +11765.269op/s] or [+5.589%; +7.486%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody netcoreapp3.1

  • 🟩 throughput [+8693.863op/s; +11435.601op/s] or [+6.926%; +9.110%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0

  • 🟩 throughput [+470027.010op/s; +483578.785op/s] or [+15.673%; +16.125%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1

  • 🟩 execution_time [-19.102ms; -14.770ms] or [-8.805%; -6.808%]
  • 🟩 throughput [+161773.866op/s; +216114.711op/s] or [+6.421%; +8.578%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net472

  • 🟥 execution_time [+299.908ms; +300.619ms] or [+149.854%; +150.209%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net6.0

  • 🟥 execution_time [+300.064ms; +303.375ms] or [+151.323%; +152.993%]
  • 🟩 throughput [+693.440op/s; +907.666op/s] or [+5.304%; +6.942%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs netcoreapp3.1

  • 🟥 execution_time [+300.012ms; +302.457ms] or [+151.123%; +152.354%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net472

  • 🟥 execution_time [+296.790ms; +297.586ms] or [+145.771%; +146.163%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0

  • 🟥 execution_time [+294.370ms; +298.813ms] or [+143.906%; +146.079%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1

  • 🟥 execution_time [+298.495ms; +301.156ms] or [+149.187%; +150.517%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net6.0

  • 🟥 execution_time [+21.006µs; +44.687µs] or [+6.706%; +14.266%]
  • 🟥 throughput [-417.448op/s; -218.202op/s] or [-13.013%; -6.802%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net472

  • 🟥 execution_time [+299.947ms; +300.668ms] or [+149.704%; +150.064%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net6.0

  • unstable execution_time [+408.593ms; +418.102ms] or [+443.953%; +454.285%]
  • 🟩 throughput [+808.834op/s; +994.403op/s] or [+6.646%; +8.171%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest netcoreapp3.1

  • unstable execution_time [+201.873ms; +265.218ms] or [+153.280%; +201.377%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟥 allocated_mem [+2.848KB; +2.853KB] or [+5.059%; +5.069%]
  • unstable execution_time [+285.722ms; +336.098ms] or [+131.372%; +154.534%]
  • 🟥 throughput [-534.695op/s; -482.680op/s] or [-48.449%; -43.736%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • unstable execution_time [+207.334ms; +340.582ms] or [+88.357%; +145.142%]
  • 🟥 throughput [-672.799op/s; -589.182op/s] or [-44.876%; -39.299%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+344.501ms; +359.482ms] or [+206.052%; +215.012%]
  • 🟥 throughput [-419.783op/s; -378.027op/s] or [-29.229%; -26.321%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0

  • 🟩 execution_time [-163.989µs; -109.932µs] or [-8.307%; -5.569%]
  • 🟩 throughput [+31.855op/s; +46.380op/s] or [+6.289%; +9.156%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net472

  • 🟥 execution_time [+305.837ms; +307.383ms] or [+154.014%; +154.792%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net6.0

  • 🟥 execution_time [+300.912ms; +302.227ms] or [+150.788%; +151.447%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch netcoreapp3.1

  • 🟥 execution_time [+299.442ms; +302.653ms] or [+150.427%; +152.040%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net472

  • 🟥 execution_time [+303.805ms; +305.771ms] or [+152.561%; +153.548%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net6.0

  • 🟥 execution_time [+301.220ms; +305.777ms] or [+148.940%; +151.193%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync netcoreapp3.1

  • 🟥 execution_time [+304.750ms; +308.418ms] or [+154.460%; +156.320%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net472

  • 🟥 execution_time [+301.658ms; +304.184ms] or [+151.405%; +152.673%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net6.0

  • 🟥 execution_time [+299.629ms; +304.147ms] or [+149.338%; +151.590%]
  • 🟩 throughput [+52807.766op/s; +58971.538op/s] or [+10.486%; +11.710%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync netcoreapp3.1

  • 🟥 execution_time [+301.433ms; +304.041ms] or [+149.960%; +151.258%]

scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net6.0

  • 🟩 execution_time [-16.637ms; -12.988ms] or [-7.736%; -6.040%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net472

  • unstable execution_time [+4.820µs; +48.443µs] or [+1.191%; +11.966%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0

  • 🟩 allocated_mem [-19.964KB; -19.940KB] or [-7.282%; -7.273%]
  • unstable execution_time [-58.376µs; -3.698µs] or [-11.538%; -0.731%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1

  • 🟩 allocated_mem [-18.393KB; -18.374KB] or [-6.705%; -6.698%]
  • unstable execution_time [-59.838µs; +1.353µs] or [-10.369%; +0.234%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net6.0

  • unstable execution_time [+7.527µs; +12.900µs] or [+17.791%; +30.491%]
  • 🟥 throughput [-5429.580op/s; -3360.063op/s] or [-22.857%; -14.145%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark netcoreapp3.1

  • unstable execution_time [-14.042µs; -5.864µs] or [-21.786%; -9.098%]
  • unstable throughput [+1520.836op/s; +3287.855op/s] or [+9.331%; +20.172%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net472

  • 🟥 execution_time [+302.045ms; +303.697ms] or [+152.670%; +153.505%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+301.641ms; +304.276ms] or [+153.534%; +154.876%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+297.592ms; +299.862ms] or [+148.981%; +150.118%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net472

  • 🟥 execution_time [+299.553ms; +301.428ms] or [+149.300%; +150.235%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+303.190ms; +304.842ms] or [+152.247%; +153.077%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+305.285ms; +307.639ms] or [+154.821%; +156.015%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net472

  • 🟥 execution_time [+300.708ms; +301.733ms] or [+149.995%; +150.506%]
  • 🟩 throughput [+61236383.629op/s; +61570531.750op/s] or [+44.596%; +44.839%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net6.0

  • 🟥 execution_time [+418.697ms; +423.420ms] or [+520.724%; +526.598%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore netcoreapp3.1

  • 🟥 execution_time [+299.538ms; +300.550ms] or [+149.403%; +149.907%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1

  • 🟩 throughput [+50637.143op/s; +71109.877op/s] or [+5.861%; +8.231%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net6.0

  • 🟩 throughput [+78053.445op/s; +107850.822op/s] or [+6.041%; +8.348%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan netcoreapp3.1

  • 🟩 throughput [+75644.738op/s; +84537.043op/s] or [+7.513%; +8.396%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net6.0

  • 🟩 throughput [+51499.426op/s; +56725.642op/s] or [+9.351%; +10.300%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1

  • 🟩 throughput [+22339.075op/s; +32358.294op/s] or [+5.000%; +7.243%]

scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0

  • 🟩 throughput [+51547.137op/s; +100289.966op/s] or [+5.759%; +11.205%]

Known flaky benchmarks without significant changes:

  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net6.0
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin netcoreapp3.1

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented May 26, 2026

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (8682) and master.

✅ No regressions detected - check the details below

Full Metrics Comparison

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration73.84 ± (73.97 - 74.51) ms72.73 ± (72.76 - 73.07) ms-1.5%
.NET Framework 4.8 - Bailout
duration77.14 ± (77.08 - 77.41) ms79.80 ± (79.48 - 79.93) ms+3.4%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1104.23 ± (1105.12 - 1111.80) ms1113.96 ± (1111.32 - 1119.11) ms+0.9%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms22.60 ± (22.55 - 22.65) ms23.01 ± (22.95 - 23.07) ms+1.8%✅⬆️
process.time_to_main_ms84.99 ± (84.74 - 85.24) ms87.77 ± (87.46 - 88.07) ms+3.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.90 ± (10.90 - 10.91) MB10.92 ± (10.92 - 10.93) MB+0.2%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.38 ± (22.34 - 22.42) ms22.56 ± (22.52 - 22.60) ms+0.8%✅⬆️
process.time_to_main_ms85.60 ± (85.40 - 85.80) ms87.00 ± (86.76 - 87.23) ms+1.6%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.94 ± (10.94 - 10.94) MB10.95 ± (10.94 - 10.95) MB+0.1%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms216.07 ± (215.20 - 216.95) ms216.65 ± (215.75 - 217.54) ms+0.3%✅⬆️
process.time_to_main_ms547.14 ± (545.78 - 548.51) ms545.59 ± (544.35 - 546.82) ms-0.3%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.49 ± (48.45 - 48.54) MB48.60 ± (48.57 - 48.63) MB+0.2%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.1%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms21.19 ± (21.14 - 21.23) ms21.62 ± (21.56 - 21.68) ms+2.0%✅⬆️
process.time_to_main_ms73.65 ± (73.45 - 73.85) ms76.22 ± (75.93 - 76.51) ms+3.5%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.61 ± (10.61 - 10.62) MB10.64 ± (10.64 - 10.64) MB+0.2%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.04 ± (21.00 - 21.08) ms21.18 ± (21.14 - 21.22) ms+0.7%✅⬆️
process.time_to_main_ms74.35 ± (74.15 - 74.55) ms74.97 ± (74.78 - 75.16) ms+0.8%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.74 ± (10.73 - 10.74) MB10.76 ± (10.76 - 10.76) MB+0.2%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms369.33 ± (367.23 - 371.43) ms369.34 ± (367.25 - 371.43) ms+0.0%✅⬆️
process.time_to_main_ms547.74 ± (546.52 - 548.96) ms553.05 ± (551.67 - 554.42) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed49.97 ± (49.95 - 49.99) MB50.06 ± (50.04 - 50.08) MB+0.2%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms19.62 ± (19.56 - 19.67) ms19.72 ± (19.66 - 19.77) ms+0.5%✅⬆️
process.time_to_main_ms74.77 ± (74.44 - 75.10) ms74.39 ± (74.14 - 74.65) ms-0.5%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.67 ± (7.67 - 7.68) MB7.71 ± (7.71 - 7.72) MB+0.5%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.40 ± (19.36 - 19.44) ms19.83 ± (19.77 - 19.89) ms+2.2%✅⬆️
process.time_to_main_ms73.95 ± (73.77 - 74.12) ms76.91 ± (76.66 - 77.16) ms+4.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.72 ± (7.72 - 7.73) MB7.76 ± (7.75 - 7.76) MB+0.4%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms297.57 ± (295.21 - 299.93) ms295.20 ± (293.04 - 297.37) ms-0.8%
process.time_to_main_ms496.68 ± (495.48 - 497.87) ms502.00 ± (500.93 - 503.06) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.96 ± (36.93 - 36.99) MB36.97 ± (36.94 - 37.00) MB+0.0%✅⬆️
runtime.dotnet.threads.count27 ± (27 - 27)27 ± (27 - 27)+0.6%✅⬆️

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration197.40 ± (197.02 - 198.02) ms198.51 ± (198.11 - 198.96) ms+0.6%✅⬆️
.NET Framework 4.8 - Bailout
duration199.01 ± (199.05 - 199.97) ms201.80 ± (201.82 - 202.61) ms+1.4%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1193.05 ± (1192.75 - 1197.97) ms1201.07 ± (1201.35 - 1207.65) ms+0.7%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms191.76 ± (191.30 - 192.23) ms192.86 ± (192.41 - 193.31) ms+0.6%✅⬆️
process.time_to_main_ms82.88 ± (82.60 - 83.16) ms83.72 ± (83.45 - 83.98) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.12 ± (16.09 - 16.15) MB16.06 ± (16.04 - 16.07) MB-0.4%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (19 - 20)-0.3%
.NET Core 3.1 - Bailout
process.internal_duration_ms192.68 ± (192.35 - 193.01) ms203.48 ± (202.70 - 204.25) ms+5.6%✅⬆️
process.time_to_main_ms84.77 ± (84.55 - 84.98) ms90.20 ± (89.67 - 90.73) ms+6.4%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.17 ± (16.14 - 16.19) MB16.07 ± (16.06 - 16.09) MB-0.6%
runtime.dotnet.threads.count21 ± (20 - 21)21 ± (21 - 21)+1.7%✅⬆️
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms386.75 ± (385.31 - 388.20) ms395.25 ± (393.48 - 397.03) ms+2.2%✅⬆️
process.time_to_main_ms535.33 ± (534.20 - 536.47) ms555.41 ± (552.56 - 558.27) ms+3.8%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed57.25 ± (57.13 - 57.38) MB58.84 ± (58.72 - 58.96) MB+2.8%✅⬆️
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.1%
.NET 6 - Baseline
process.internal_duration_ms196.53 ± (196.07 - 196.99) ms196.83 ± (196.32 - 197.33) ms+0.2%✅⬆️
process.time_to_main_ms72.04 ± (71.83 - 72.25) ms71.90 ± (71.67 - 72.13) ms-0.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.36 ± (16.32 - 16.39) MB16.37 ± (16.34 - 16.39) MB+0.1%✅⬆️
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.3%✅⬆️
.NET 6 - Bailout
process.internal_duration_ms195.93 ± (195.51 - 196.34) ms194.70 ± (194.23 - 195.16) ms-0.6%
process.time_to_main_ms72.64 ± (72.45 - 72.83) ms72.46 ± (72.28 - 72.64) ms-0.3%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.45 ± (16.42 - 16.49) MB16.44 ± (16.42 - 16.47) MB-0.1%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)-0.4%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms587.26 ± (585.17 - 589.36) ms583.84 ± (581.44 - 586.25) ms-0.6%
process.time_to_main_ms542.42 ± (541.36 - 543.48) ms546.06 ± (545.14 - 546.97) ms+0.7%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed61.13 ± (61.04 - 61.21) MB61.15 ± (61.07 - 61.23) MB+0.0%✅⬆️
runtime.dotnet.threads.count31 ± (31 - 31)31 ± (31 - 31)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms194.65 ± (194.23 - 195.06) ms196.63 ± (196.26 - 197.01) ms+1.0%✅⬆️
process.time_to_main_ms71.61 ± (71.35 - 71.88) ms71.87 ± (71.60 - 72.13) ms+0.4%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.69 ± (11.67 - 11.71) MB11.71 ± (11.69 - 11.73) MB+0.2%✅⬆️
runtime.dotnet.threads.count18 ± (18 - 19)18 ± (18 - 18)-1.2%
.NET 8 - Bailout
process.internal_duration_ms193.57 ± (193.22 - 193.92) ms194.84 ± (194.45 - 195.24) ms+0.7%✅⬆️
process.time_to_main_ms72.46 ± (72.27 - 72.65) ms72.83 ± (72.63 - 73.03) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.76 ± (11.74 - 11.79) MB11.74 ± (11.72 - 11.76) MB-0.2%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-0.1%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms513.85 ± (511.39 - 516.30) ms512.71 ± (510.08 - 515.35) ms-0.2%
process.time_to_main_ms490.26 ± (489.41 - 491.11) ms497.58 ± (496.67 - 498.49) ms+1.5%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed50.56 ± (50.52 - 50.59) MB50.67 ± (50.64 - 50.71) MB+0.2%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 30)+0.8%✅⬆️
Comparison explanation

Execution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).

Duration charts
FakeDbCommand (.NET Framework 4.8)
gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (73ms)  : 71, 75
    master - mean (74ms)  : 70, 78

    section Bailout
    This PR (8682) - mean (80ms)  : 76, 83
    master - mean (77ms)  : 75, 79

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (1,115ms)  : 1058, 1173
    master - mean (1,108ms)  : 1060, 1157

Loading
FakeDbCommand (.NET Core 3.1)
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (118ms)  : 112, 124
    master - mean (115ms)  : 110, 120

    section Bailout
    This PR (8682) - mean (116ms)  : 112, 121
    master - mean (115ms)  : 112, 117

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (798ms)  : 773, 823
    master - mean (799ms)  : 776, 822

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (105ms)  : 98, 111
    master - mean (101ms)  : 97, 105

    section Bailout
    This PR (8682) - mean (103ms)  : 99, 106
    master - mean (102ms)  : 99, 105

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (953ms)  : 917, 989
    master - mean (950ms)  : 915, 984

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (102ms)  : 97, 108
    master - mean (102ms)  : 96, 109

    section Bailout
    This PR (8682) - mean (105ms)  : 100, 110
    master - mean (101ms)  : 97, 105

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (829ms)  : 781, 878
    master - mean (827ms)  : 781, 873

Loading
HttpMessageHandler (.NET Framework 4.8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (199ms)  : 194, 203
    master - mean (198ms)  : 191, 204

    section Bailout
    This PR (8682) - mean (202ms)  : 198, 206
    master - mean (200ms)  : 195, 204

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (1,204ms)  : 1165, 1244
    master - mean (1,195ms)  : 1160, 1231

Loading
HttpMessageHandler (.NET Core 3.1)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (286ms)  : 274, 297
    master - mean (284ms)  : 276, 291

    section Bailout
    This PR (8682) - mean (303ms)  : crit, 282, 324
    master - mean (286ms)  : 281, 291

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (992ms)  : 922, 1061
    master - mean (963ms)  : 945, 981

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (277ms)  : 269, 285
    master - mean (277ms)  : 272, 282

    section Bailout
    This PR (8682) - mean (276ms)  : 267, 286
    master - mean (277ms)  : 272, 282

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (1,159ms)  : 1121, 1198
    master - mean (1,160ms)  : 1118, 1202

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8682) - mean (279ms)  : 273, 284
    master - mean (276ms)  : 271, 282

    section Bailout
    This PR (8682) - mean (278ms)  : 273, 283
    master - mean (276ms)  : 271, 281

    section CallTarget+Inlining+NGEN
    This PR (8682) - mean (1,042ms)  : 995, 1089
    master - mean (1,035ms)  : 991, 1079

Loading

christophe-papazian and others added 2 commits May 26, 2026 12:56
The DoesNotTagWhenHeadersAreAbsent theory added a "content-type"
header to a WebHeaderCollection to populate an unrelated header.
On .NET Framework, WebHeaderCollection.Add throws on well-known
request headers including Content-Type. .NET Core / .NET 5+ relaxed
this, so the test passed locally on net8.0 but failed in CI on net48.

Swap "content-type" for a custom "x-other-header" name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@e-n-0 e-n-0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!
I would add also an integration test with a snapshot file to validate that the tags are correctly set. Please look at the sample app

Comment thread tracer/src/Datadog.Trace/Propagators/SpanContextPropagator.cs Outdated
Comment thread tracer/src/Datadog.Trace/Propagators/SpanContextPropagator.cs Outdated
christophe-papazian and others added 3 commits May 26, 2026 16:43
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per @e-n-0's review: add a snapshot-based integration test that
sends a request to Samples.Security.AspNetCore5 with the scan/test
marker headers and verifies they appear as http.request.headers.*
tags on the entry span. Lives in AspNetCore5TestsWithoutExternalRulesFile
so it runs under both SecurityDisabled and SecurityEnabled fixtures —
proves the unconditional-tagging contract regardless of AppSec.

Snapshots will be generated on first CI run and committed in a
follow-up after review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated from CI build 202229. Both snapshots show the entry
span carrying http.request.headers.x-datadog-endpoint-scan and
http.request.headers.x-datadog-security-test. The SecurityEnabled
snapshot additionally includes _dd.appsec.* tags, proving the
markers don't interfere with AppSec being on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@christophe-papazian christophe-papazian requested a review from e-n-0 May 27, 2026 08:51

@e-n-0 e-n-0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM Thanks!

@christophe-papazian christophe-papazian marked this pull request as ready for review May 27, 2026 09:11
@christophe-papazian christophe-papazian merged commit 7174a42 into master May 27, 2026
138 checks passed
@christophe-papazian christophe-papazian deleted the christophe.papazian/appsec-65483-security-testing-headers branch May 27, 2026 09:11
@github-actions github-actions Bot added this to the vNext-v3 milestone May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:asm type:enhancement Improvement to an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants