Skip to content

Fix partial query redaction caused by encoded ampersands - #12995

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
masterfrom
mcculls/fix-http-query-redaction
Oct 23, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
masterfrom
mcculls/fix-http-query-redaction

Conversation

@mcculls

@mcculls mcculls commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

What Does This Do

Preserve %26 and %23 in otherwise decoded query strings so encoded value characters retain their parameter and fragment boundaries. Apply this to HTTP client spans and to server spans when http.server.raw.query-string=false and raw queries are available.

Motivation

Decoding token=first%26SECOND_HALF&view=full before redaction turned %26 into a literal &, causing sensitive parameter redaction to stop early and expose SECOND_HALF in http.query and http.url. The query now becomes <redacted>&view=full, while encoded parameter names remain decoded for sensitive-name matching.

Additional Notes

Java has used decoded client queries (URI.getQuery()) since query tagging was introduced in 2019, before query obfuscation was added in 2022. The obfuscator can process raw queries, as other tracers do, but switching to getRawQuery() would change reported tag values and the input seen by custom obfuscation regexes. This fix preserves the existing decoded representation while retaining encoded delimiters, and continues to decode parameter names such as t%6fken for sensitive-name matching. Server spans already support raw queries; this change covers the explicitly decoded mode when raw queries are available.

Formatting checks passed for internal-api, dd-trace-core, and agent-bootstrap. Targeted tests passed:

  • URIUtilsTest
  • QueryObfuscatorTest
  • HttpClientDecoratorTest and HttpServerDecoratorTest
  • HttpClientQueryRedactionForkedTest, including assertions on the written span's http.query and http.url

Contributor Checklist

  • Use an imperative title and component/type labels.
  • Run formatting checks and targeted regression tests.
  • Confirm the new test is covered by existing CODEOWNERS rules.

@mcculls mcculls added type: bug fix Bug fix comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM labels Oct 22, 2026
@mcculls
mcculls force-pushed the mcculls/fix-http-query-redaction branch from 06ff9e2 to 476c2f9 Compare October 22, 2026 16:16
@mcculls
mcculls marked this pull request as ready for review October 22, 2026 16:16
@mcculls
mcculls requested review from a team as code owners October 22, 2026 16:16
@mcculls
mcculls requested review from anna-git and sarahchen6 and removed request for a team October 22, 2026 16:16
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T16:19:36.635285Z 476c2f9 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@mcculls
mcculls requested review from PerfectSlayer and dougqh and removed request for anna-git October 22, 2026 16:16
datadog-datadog-prod-us1-2[bot]

This comment was marked as outdated.

@mcculls
mcculls force-pushed the mcculls/fix-http-query-redaction branch from 476c2f9 to 9d71c1f Compare October 22, 2026 16:31
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
• Patch Coverage: 91.49%
• Overall Coverage: 59.47% (-0.35%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 627effe | Docs | Give us feedback!

@mcculls

mcculls commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

@DataDog review

@sarahchen6 sarahchen6 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice

datadog-datadog-prod-us1-2[bot]

This comment was marked as outdated.

HTTP client spans tagged http.query with the decoded query, so an
encoded %26 in a value became a literal '&'. Sensitive parameter
redaction stopped there, exposing the remainder in http.query and
http.url.

Preserve %26 and %23 when decoding queries to retain parameter and
fragment boundaries. Apply this to client spans and to server spans
when http.server.raw.query-string=false and raw queries are available.
@mcculls
mcculls force-pushed the mcculls/fix-http-query-redaction branch from 9d71c1f to 627effe Compare October 22, 2026 16:56
@mcculls

mcculls commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

@DataDog review

@dd-octo-sts

dd-octo-sts Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.05 s 13.99 s [-0.3%; +1.1%] (no difference)
startup:insecure-bank:tracing:Agent 13.02 s 12.96 s [-0.4%; +1.2%] (no difference)
startup:petclinic:appsec:Agent 17.08 s 17.00 s [-0.5%; +1.5%] (no difference)
startup:petclinic:iast:Agent 16.96 s 16.97 s [-0.9%; +0.7%] (no difference)
startup:petclinic:profiling:Agent 16.56 s 16.82 s [-2.5%; -0.6%] (maybe better)
startup:petclinic:sca:Agent 17.04 s 16.94 s [-0.4%; +1.5%] (no difference)
startup:petclinic:tracing:Agent 16.08 s 16.09 s [-1.0%; +0.9%] (no difference)

Commit: 627effe3 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bits Code Review: PASS

More details

Focused generated-query checks supported correct delimiter preservation across Java 21 and Java 8 decoder behavior, including bracketed queries. The completed static review returned no actionable findings.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit 627effe

@mcculls
mcculls added this pull request to the merge queue Oct 23, 2026
@dd-octo-sts

dd-octo-sts Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-10-23 08:20:23 UTC ℹ️ Start processing command /merge


2026-10-23 08:20:28 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 1h (p90).


2026-10-23 09:47:02 UTC ℹ️ MergeQueue: This merge request was merged

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 23, 2026
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit 79a425a into master Oct 23, 2026
609 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the mcculls/fix-http-query-redaction branch October 23, 2026 09:47
@github-actions github-actions Bot added this to the 1.68.0 milestone Oct 23, 2026
mcculls added a commit that referenced this pull request Oct 23, 2026
Preserve the query delimiter redaction fix from #12995 in the Datadog and OpenTelemetry URL extractors, retaining both branches' regression coverage.
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Oct 23, 2026
Configure required settings for OpenTelemetry HTTP semantics:
- Http client error status codes default to 400-600 (instead of 400-500)
- The environment variable DD_TRACE_OTEL_SEMANTICS_ENABLED automatically configures the following
  - OTEL_TRACES_EXPORTER=otlp
  - DD_WRITER_TYPE=OtlpWriter
  - DD_TRACE_SPAN_ATTRIBUTE_SCHEMA=v0
  - DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=false

Add the following tags:

http:
- http.request.method_original (OTel)
- server.address (OTel)
- server.port (OTel)

http.server:
- url.path (OTel)
- url.query (OTel)
- url.scheme (OTel)

mixins:
  peer:
    tags:
      - network.peer.address (OTel)
      - peer.port (DD) => network.peer.port (OTel)

Map peer port to the OTel network attribute

Fixup http tag conventions. Squash so we can edit the message

Implement OpenTelemetry HTTP client semantic conventions

Implement OpenTelemetry HTTP server semantic conventions

Test end-to-end OpenTelemetry HTTP client semantics

- Apache HTTP client
- Apache HTTP Async Client
- Google HTTP Client
- HttpURLConnection
- JAX-RS Client
- OkHttp
- Play WSClient

Test end-to-end OpenTelemetry HTTP server semantics
- Akka-Http Server
- JAX-RS Server
- Jersey Server
- Jetty
- Netty HTTP server
- Servlet
- Play HTTP server
- Ratpack HTTP server
- Spring MVC
- Spring WebFlux
- Tomcat
- Undertow
- Vert.x

PR feedback on logic/processing, avoiding tags definitions:
- Restore IP tags collection so it is opt-in. The DD->OTel tag mapping remains
- Restore query tags collection so it honors the user's query tag opt-out
- Improve OtelHttpSemantics.parsePort performance (especially since this can be influenced by a user)
- Stores the OTel http client span's "url.full" URL in a lazy wrapper so redaction and query removal only occur at export time

PR feedback on tag-conventions: Restore network.client.ip so it is not span-kind-neutral

PR feedback on tag-conventions: Fix the tag definitions of OTel server.port and server.address while keeping the span direction relationships correct

HTTP server spans:
- http.server: restore "http.hostname" => OTel "server.address"
- http.server: add standalone (OTel-only) "server.port"

HTTP client spans:
- outbound_peer: restore "peer.hostname" => OTel "server.address"
- outbound_peer: restore "peer.port" => OTel "server.port"

Polish: Update the obfuscator tag name for OpenTelemetry semantics to DDTags.HTTP_QUERY_OTEL_NAME, which mimics DDTags.HTTP_QUERY so we have one consistent tag name

Polish: Update setters to use IDs rather than tag names

Fix: Add regression tests for identified errors when enabling the opt-in changes, including:

HttpDecoratorsOtelSemanticsForkedTest.java
- Elasticsearch and OpenSearch spans should be unchanged
- There must not be duplicate attributes for client destination ports (server.port)
- InferredProxySpan should record server.port=443 due to the default https scheme
- When OTel semantics are enabled, Forwarded-header extraction should be run and determine client span attributes, even if DD_TRACE_CLIENT_IP_ENABLED=false or AppSec+AI Guard are disabled
- When OTel semantics are enabled, url.full (OTel equivalent of http.url) decodes the query before storing and sending to QueryObfuscator.

OtelHttpSemanticsTest.java
- When OTel semantics are enabled, url.full (OTel equivalent of http.url) decodes the query before storing and sending to QueryObfuscator.

HttpClientPathMappingOtelSemanticsForkedTest.java
- TRACE_HTTP_CLIENT_PATH_RESOURCE_NAME_MAPPING takes precedence and replaces the http.route placeholder in the OTel HTTP server span name "{http.request.method} {http.route}"

LambdaHttpOtelSemanticsForkedTest.java & LambdaAppSecHandlerTest.java
- Lambda query tags should continue to be obfuscated

GatewayBridgeOtelSemanticsForkedTest.java
- API Security must continue to fall back to the http.url span attribute when the server span does not have an http.route span attribute

Fix: Implement fixes for the noted regressions

Fix: Address two issues identified by automated code review.

- QueryObfuscator: Obfuscate both the DD and OTel query string tags as a preventative measure to make sure we do not store an unobfuscated query string on a span. When OTel semantics mode is enabled, the OTel value will be take precedence as the final recorded value (the DD value will be discarded if present).
- Ensure that we record the correct origin port when handling forwarded schemes

fix linting issue

Apply spotless formatting

Fix: Address issues identified by automated code review:
- Correct obfuscated-query expectations
- Fix the IAST missing-HSTS detection by allowing it to also check the "url.scheme" OTel HTTP server tag to confirm HTTPS, since the "http.url" tag is only emitted with DD semantic conventions

PR feedback: Address the following issues:
- In the BaseDecorator.setPeerPort methods (used by both clients and servers), set the tag via the directionless KnownTags.PEER_PORT_ID key.
- In HttpServerDecorator, strip the query and fragment from the URL before setting the OTel attribute "url.path". Also, set the OTel attribute "url.query" if a query string is present
- In AxwayHTTPPluginDecorator make sure to honor the query opt-out before setting the OTel attribute "url.query"

PR Feedback: Remove DDTags.HTTP_QUERY_OTEL_NAME (public API) and use KnownTags.URL_QUERY_NAME (OTel "url.query") in its place

PR Feedback: Use the TagExtractor infrastructure to simplify setting the url-based tags on http clients and servers, for both Datadog and OTel semantics.

Key details include:
- HttpServerUrl is created as an abstract class to expose a consistent interface for accessing underlying URL facts from various request objects -- there is no equivalent for client spans as the logic is simple enough that operating on a URL object is sufficient
- OtelServerUrl and DatadogServerUrl implement TagExtractor<HttpServerUrl> to provide the "OTEL_SEMANTICS branching" for populating http server span tags
- DatadogClientUrl and OtelClientUrl  implement TagExtractor<URI> to provide the "OTEL_SEMANTICS branching" for populating http client span tags
- The host and hostPort calculations from OtelHttpSemantics.setServerAddressAndPort are migrated to HttpServerUrl.Origin.resolve
- Additional logic from OtelHttpSemantics is ported to the new UrlExtractors, so a handful of tests in OtelHttpSemanticsTest.java are simply ported to HttpUrlExtractorsTest.java
- HttpUrlExtractorsTest.java provides testing of the TagExtractor implementations

Preserve default HTTP behavior with OTel semantics disabled

Preserve existing query concatenation for captured URLs with decoded
path characters when OTel semantics are disabled. Restore port-based
service splitting precedence and skip the OTel-only Host header lookup
in that mode.

Add regression coverage for all three issues. Each new regression failed
before the fixes; all 102 selected query obfuscator and decorator tests
now pass, including existing OTel and client path-mapping coverage.

Simplify HTTP URL string assembly

Use string concatenation and trailing substrings when inserting or removing queries while retaining fragments. Verify query obfuscation, HTTP semantics helpers, URL extractors, and OTel decorators with their existing tests and formatting checks.

Cleanup: Update tag-conventions to allow "http.query.string" (DD) to map to "url.query" (OTel), to simplify query obfuscation

Cleanup:
- Remove the unused origin caches in HttpServerUrl (only used once per request)
- Simplify inferred proxy resource naming
- Refactor the "FullUrl" extractor into URLConnection where it is exclusively used today
- In OtelHttpSemantics, reuse parseNonNegativeInt in the parsePort logic
- In HttpServerDecorator, avoid rereading a client IP from tags that were just set
- Add a shared URL fallback that GatewayBridge and HttpEndpointPostProcessor can use for getting the "http.url" first then "url.path" if null
- Inherit the OTEL_SEMANTICS boolean in AxwayHTTPPluginDecorator
- Clean upthe http client span resource name setting

Fix query obfuscator URL expectations for Datadog semantics

Commit 8a57978 added Datadog server and client cases while retaining the OTel-only expected URL. Datadog semantics deliberately append queries after the captured path to preserve decoded hash characters, as established by ba672e9.

Specify the expected URL per scenario while preserving query retention checks for both semantics modes. No production behavior changes.

Validation: reproduced 2 failures out of 34 cases before the fix; all 34 QueryObfuscatorTest cases pass after it. Ran :dd-trace-core:spotlessApply and git diff --check.

Keep Datadog and OpenTelemetry query tags separate

Aliasing url.query to http.query.string in the tag registry applies even
when OTel semantics are disabled. It changes exported tag names, merges
independently supplied values, and routes url.query through the legacy
query appender. A complete URL such as /orders?page=1 can consequently
become /orders?page=1?page=1.

These tags are not interchangeable: http.query.string feeds legacy URL
reconstruction, while url.query may accompany an already complete URL.
Keep distinct registry entries and have the OTel producers select
url.query explicitly, including the Lambda HTTP path.

Share redaction between the tags, process url.query only when OTel
semantics are enabled, and replace any existing query before the fragment
when rebuilding an OTel URL. Preserve the original URL concatenation and
leave separately supplied url.query tags untouched in default mode.

Validation: 891 selected query, registry, URL, HTTP decorator, Lambda and
OTLP tests passed. All 176 emitted-tag comparisons against local master
matched across eight default-mode query/raw-query/raw-resource settings.

Reduce retained memory in lazy OpenTelemetry client URLs

The lazy client URL wrapper kept its original URI after rendering, retaining
query data that was excluded from the exported URL even when query capture
was disabled. A 100,035-character input URI remained reachable through a
wrapper whose rendered URL was only 26 characters.

Cache the rendered URL and decoded path, then release the source URI. This
reduces retained heap after rendering while preserving deferred URL assembly
and redaction on the request path. It also avoids recomputing the URL when
get() is called directly more than once.

Publish the cached values before clearing the volatile URI reference so
concurrent readers can safely use either their local URI or the cached data.

Validation: 323 selected URL, query-obfuscation and HTTP semantics tests
passed, including repeated supplier/string reads and concurrent path reads
and rendering. The long-query probe confirms that the wrapper releases its
source URI after rendering with query capture disabled.

Fix server query tag assertions for OpenTelemetry semantics

Cover HTTP URL extractor edge cases

Fix query tag assertions for OpenTelemetry HTTP semantics

Simplify OpenTelemetry HTTP client resource name fallback

Merge origin/master into otel-http-semconv

Preserve the query delimiter redaction fix from #12995 in the Datadog and OpenTelemetry URL extractors, retaining both branches' regression coverage.

Co-authored-by: mcculls <stuart.mcculloch@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM type: bug fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants