From 396b423c568e67f7dcd62a4442e5aaa832a2141c Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Wed, 17 Jun 2026 11:02:32 -0400 Subject: [PATCH 1/2] Fix AppSec/IAST context dropped when trace.propagation.behavior.extract=ignore/restart With IGNORE or RESTART, CoreSpanBuilder nulls the remote TagContext parent before buildSpanContext reaches the instanceof TagContext branch that copies requestContextDataAppSec/requestContextDataIast. The AppSec context is lost and GatewayBridge callbacks no-op, silently bypassing WAF/RASP for all inbound requests in AppSec-enabled services configured to ignore distributed tracing extraction. Fix: promote the AppSec/IAST data from the TagContext into the builder fields before nulling the parent. The builder-field path in buildSpanContext applies these after the parent is gone, preserving the request context while still correctly dropping trace identifiers and sampling priority. Fixes: APMSP-3198 Co-Authored-By: Claude Sonnet 4.6 --- .../java/datadog/trace/core/CoreTracer.java | 12 ++++++++ .../trace/core/CoreSpanBuilderTest.java | 30 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 59325f25632..9fe183b10a7 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -1790,6 +1790,18 @@ protected static final AgentSpan startSpan( // Handle remote terminated span context as span links if (parentSpanContext != null && parentSpanContext.isRemote()) { + // Preserve AppSec/IAST request context before dropping the remote parent: when + // extract=IGNORE or RESTART the TagContext parent is nulled before buildSpanContext + // can copy requestContextDataAppSec/Iast into DDSpanContext. + if (parentSpanContext instanceof TagContext) { + TagContext tc = (TagContext) parentSpanContext; + if (builderRequestContextDataAppSec == null) { + builderRequestContextDataAppSec = tc.getRequestContextDataAppSec(); + } + if (builderRequestContextDataIast == null) { + builderRequestContextDataIast = tc.getRequestContextDataIast(); + } + } switch (Config.get().getTracePropagationBehaviorExtract()) { case RESTART: links = addParentSpanLink(links, parentSpanContext); diff --git a/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java b/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java index 000598ca7c9..f729840f5ef 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java @@ -422,6 +422,36 @@ void buildContextFromExtractedContextWithIgnoreBehavior() { assertTrue(span.getLinks().isEmpty()); } + @Test + @WithConfig(key = "trace.propagation.behavior.extract", value = "ignore") + void appSecContextPreservedFromTagContextWithIgnoreBehavior() { + Object appSecData = new Object(); + Object iastData = new Object(); + TagContext tagContext = + new TagContext().withRequestContextDataAppSec(appSecData).withRequestContextDataIast(iastData); + + DDSpan span = (DDSpan) tracer.buildSpan("test", "op name").asChildOf(tagContext).start(); + + assertEquals(appSecData, span.getRequestContext().getData(RequestContextSlot.APPSEC)); + assertEquals(iastData, span.getRequestContext().getData(RequestContextSlot.IAST)); + span.finish(); + } + + @Test + @WithConfig(key = "trace.propagation.behavior.extract", value = "restart") + void appSecContextPreservedFromTagContextWithRestartBehavior() { + Object appSecData = new Object(); + Object iastData = new Object(); + TagContext tagContext = + new TagContext().withRequestContextDataAppSec(appSecData).withRequestContextDataIast(iastData); + + DDSpan span = (DDSpan) tracer.buildSpan("test", "op name").asChildOf(tagContext).start(); + + assertEquals(appSecData, span.getRequestContext().getData(RequestContextSlot.APPSEC)); + assertEquals(iastData, span.getRequestContext().getData(RequestContextSlot.IAST)); + span.finish(); + } + @TableTest({ "scenario | origin | tagMap ", "empty tag map | | [:] ", From 10a4deda1e5e2e27e3cee7e4af25c11de3940844 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Wed, 24 Jun 2026 10:57:17 -0400 Subject: [PATCH 2/2] Apply spotless formatting Co-Authored-By: Claude Sonnet 4.6 --- .../test/java/datadog/trace/core/CoreSpanBuilderTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java b/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java index f729840f5ef..45b559707bf 100644 --- a/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/CoreSpanBuilderTest.java @@ -428,7 +428,9 @@ void appSecContextPreservedFromTagContextWithIgnoreBehavior() { Object appSecData = new Object(); Object iastData = new Object(); TagContext tagContext = - new TagContext().withRequestContextDataAppSec(appSecData).withRequestContextDataIast(iastData); + new TagContext() + .withRequestContextDataAppSec(appSecData) + .withRequestContextDataIast(iastData); DDSpan span = (DDSpan) tracer.buildSpan("test", "op name").asChildOf(tagContext).start(); @@ -443,7 +445,9 @@ void appSecContextPreservedFromTagContextWithRestartBehavior() { Object appSecData = new Object(); Object iastData = new Object(); TagContext tagContext = - new TagContext().withRequestContextDataAppSec(appSecData).withRequestContextDataIast(iastData); + new TagContext() + .withRequestContextDataAppSec(appSecData) + .withRequestContextDataIast(iastData); DDSpan span = (DDSpan) tracer.buildSpan("test", "op name").asChildOf(tagContext).start();