feat(appsec): collect Datadog security-testing headers on entry spans#8463
Conversation
🎉 All green!❄️ No new flaky tests detected 🎯 Code Coverage (details) 🔗 Commit SHA: e6c4720 | Docs | Datadog PR Page | Give us feedback! |
| }) | ||
| }) | ||
|
|
||
| describe('security testing headers', () => { |
There was a problem hiding this comment.
a bit too "unit-y" for my taste, it doesn't test a header is tagged (even with appsec disabled), it tests the function works when stubbed, but up to you/APM
There was a problem hiding this comment.
Keeping the unit tests since you flagged this as optional. The four scenarios (collected / absent / unconditional vs headerTags / empty value) directly exercise the contract through web.finishAll, which is the same seam every plugin span uses. Happy to add an integration-style spec in a follow-up if APM wants stronger coverage.
Tag `x-datadog-endpoint-scan` and `x-datadog-security-test` request headers on service entry spans as `http.request.headers.<name>`, unconditionally — regardless of `DD_TRACE_HEADER_TAGS` or AppSec being enabled. These markers let the API endpoint reducer distinguish Datadog scan/test traffic from real user traffic and keep it out of the API inventory. Headers are not propagated downstream (dd-trace-js only injects tracer headers into outgoing requests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inline the two header tag-sets directly into addRequestTags, drop the helper function and SECURITY_TESTING_HEADERS array (only two markers will ever exist). Remove inferred-proxy span tagging — RFC only mandates the service entry span. Drop the lowercase-normalization regression test and the inferred-proxy test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e32bf12 to
e6c4720
Compare
Overall package sizeSelf size: 5.85 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-05-15 13:04:14 Comparing candidate commit e6c4720 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 1483 metrics, 110 unstable metrics. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6c4720807
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
LGTM but this is not our turf, deferring approval to the codeowners |
…#8463) * feat(appsec): collect Datadog security-testing headers on entry spans Tag `x-datadog-endpoint-scan` and `x-datadog-security-test` request headers on service entry spans as `http.request.headers.<name>`, unconditionally — regardless of `DD_TRACE_HEADER_TAGS` or AppSec being enabled. These markers let the API endpoint reducer distinguish Datadog scan/test traffic from real user traffic and keep it out of the API inventory. Headers are not propagated downstream (dd-trace-js only injects tracer headers into outgoing requests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(appsec): address review feedback on security-testing headers Inline the two header tag-sets directly into addRequestTags, drop the helper function and SECURITY_TESTING_HEADERS array (only two markers will ever exist). Remove inferred-proxy span tagging — RFC only mandates the service entry span. Drop the lowercase-normalization regression test and the inferred-proxy test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…#8463) * feat(appsec): collect Datadog security-testing headers on entry spans Tag `x-datadog-endpoint-scan` and `x-datadog-security-test` request headers on service entry spans as `http.request.headers.<name>`, unconditionally — regardless of `DD_TRACE_HEADER_TAGS` or AppSec being enabled. These markers let the API endpoint reducer distinguish Datadog scan/test traffic from real user traffic and keep it out of the API inventory. Headers are not propagated downstream (dd-trace-js only injects tracer headers into outgoing requests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(appsec): address review feedback on security-testing headers Inline the two header tag-sets directly into addRequestTags, drop the helper function and SECURITY_TESTING_HEADERS array (only two markers will ever exist). Remove inferred-proxy span tagging — RFC only mandates the service entry span. Drop the lowercase-normalization regression test and the inferred-proxy test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ry spans (#8682) ## 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"](https://docs.google.com/document/d/1uR4QQvU8pItEV2zFqr3-L6jO2jxzmvLrFTX_yyvqIOA). 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`](DataDog/dd-trace-py#18049), [`dd-trace-js#8463`](DataDog/dd-trace-js#8463), [`dd-trace-java#11418`](DataDog/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 <!-- Fixes #{issue} --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
APPSEC-63246
What does this PR do?
Tags two Datadog markers —
x-datadog-endpoint-scanandx-datadog-security-test— on incoming HTTP server spans ashttp.request.headers.<name>. Collection is unconditional: independent ofDD_TRACE_HEADER_TAGSand AppSec enablement.Motivation
Lets the API endpoint reducer distinguish Datadog scan/test traffic from real user traffic and keep it out of the API inventory.
Additional Notes
packages/dd-trace/src/plugins/util/web.jsso it fires on every in-tree HTTP server entry path (http,http2, Azure Functions, Express, Fastify, Hapi, Koa, Next.js, …). Inferred proxy span is tagged too.tracer.inject(); nothing copies arbitrary incoming headers into outgoing ones.http.request.headers.<name>), matching dd-trace-py. The OTel-style variant is handled by the reducer, not by tracers.Test plan
packages/dd-trace/test/plugins/util/web.spec.js(6 new): collected when present, absent when missing, unconditional vsDD_TRACE_HEADER_TAGS, empty value still tagged, lowercase-normalization regression, inferred proxy span coverage.🤖 Generated with Claude Code