FrankChen021 commented on code in PR #19572:
URL: https://github.com/apache/druid/pull/19572#discussion_r3388206173
##########
server/src/main/java/org/apache/druid/server/QueryLifecycle.java:
##########
@@ -227,6 +238,28 @@ public void initialize(final Query<?> baseQuery)
Map<String, Object> finalContext =
QueryContexts.override(contextWithDefaults, baseQuery.getContext());
finalContext.put(BaseQuery.QUERY_ID, queryId);
+ // Anti-spoof + propagation. Strip user-supplied values for all reserved
keys, then
+ // inject filter-captured values for headers actually present on this
request. Reserved
+ // keys can ONLY originate from a filter-captured header — which means
either a real
+ // client request (entry point) or an inter-Druid RPC where the upstream
Druid node
+ // attached the header onto the wire (see
DirectDruidClient.applyToOutboundRequest).
+ // Without the strip, a malicious client could supply
{"context":{"traceId":"forged"}}
+ // in the query JSON body and have it survive into OpenLineage / Atlas /
audit.
+ //
+ // Trade-off: if an intermediate L7 proxy strips the custom X- header
between two
+ // Druid nodes, the propagated value is lost on the receiving node (no
fallback to
+ // the body-context value, which was just stripped). Druid's internal RPCs
are
+ // expected to be direct (broker→historical etc.) rather than mediated by a
+ // header-rewriting proxy. Operators running a mesh that strips custom X-*
headers
+ // should add the configured headers to their mesh's allow-list.
+ for (String reservedKey :
requestHeaderContextConfig.getHeaderToContextKey().values()) {
+ finalContext.remove(reservedKey);
+ }
+ final Map<String, String> captured = RequestHeaderContext.current();
+ if (!captured.isEmpty()) {
+ finalContext.putAll(captured);
Review Comment:
P2 Header-mapped context bypasses context authorization
Captured request headers are merged into the final query context here, but
these keys were not included in the user context keys that
AuthConfig.contextKeysToAuthorize checks. Since RequestHeaderContextConfig only
rejects queryId/subQueryId/sqlQueryId, an operator can map a client-controlled
header to existing operational context keys such as priority, lane, or cache
flags; clients can then set those values via headers without the QUERY_CONTEXT
WRITE authorization required for the same keys in the query body. Please either
reject mappings to existing Druid query-context keys or include captured header
target keys in context authorization unless they come from a trusted internal
source.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]