Andrea Cosentino created CAMEL-24730:
----------------------------------------
Summary: camel-spiffe - do not let inbound headers choose the
operation or the validated audience
Key: CAMEL-24730
URL: https://issues.apache.org/jira/browse/CAMEL-24730
Project: Camel
Issue Type: Bug
Reporter: Andrea Cosentino
Assignee: Andrea Cosentino
h2. Problem
{{SpiffeProducer}} reads two security-relevant inputs from the message *in
preference to* the endpoint configuration:
{code:java}
private SpiffeOperation determineOperation(Exchange exchange) {
SpiffeOperation operation =
exchange.getIn().getHeader(SpiffeConstants.OPERATION, SpiffeOperation.class);
return operation != null ? operation :
getEndpoint().getConfiguration().getOperation();
}
private String[] resolveAudiences(Exchange exchange) {
String audience = exchange.getIn().getHeader(SpiffeConstants.AUDIENCE,
String.class);
if (ObjectHelper.isEmpty(audience)) {
audience = getEndpoint().getConfiguration().getAudience();
}
...
}
{code}
Both were reproduced against a route configured as a validator
({{operation=validateJwtSvid&audience=spiffe://example.org/my-service}}) with a
mocked {{WorkloadApiClient}}:
{noformat}
configured audience = spiffe://example.org/my-service
VALIDATED AGAINST = spiffe://example.org/ATTACKER-CHOICE <-
CamelSpiffeAudience wins
OPERATION FLIPPED TO MINT = true <- body =
minted token
validateJwtSvid never called
{noformat}
h3. (a) The audience is the check, not a parameter
For {{validateJwtSvid}} the audience is what binds the token to *this* service
- it is the {{aud}} claim check. Letting the message pick it means a JWT-SVID
minted for a different workload validates successfully, and the route then
treats the caller as authenticated. This is the same shape as CAMEL-24281 /
CVE-2026-66908, where platform-http-main did not enforce {{iss}}/{{aud}}.
Note this is specific to *validation*. For {{fetchJwtSvid}} the audience is a
genuine per-message parameter ("mint me a token for X") and the header override
there is correct.
h3. (b) A validator can be turned into a minter
{{CamelSpiffeOperation: fetchJwtSvid}} against an endpoint configured for
{{validateJwtSvid}} makes the workload mint and return *its own* JWT-SVID to
the caller - an identity-credential disclosure, not just a bypass.
h2. Severity and reachability
This is *defense in depth*, not a reachable-by-default vulnerability: per the
Camel security model external senders are untrusted, but a well-behaved
consumer applies a {{HeaderFilterStrategy}} that blocks {{Camel*}} headers, so
the obvious HTTP path is already closed. It matters because the component's
entire purpose is workload identity, and because the sibling component already
takes the opposite - and safer - position:
{quote}
The path is taken from the endpoint only: it is deliberately not overridable by
a message header, so an inbound message cannot pick which policy judges it. --
{{OpaEndpoint#policyPath}}
{quote}
{{camel-opa}} pins its policy path for exactly this reason. {{camel-spiffe}}
should be consistent.
h2. Proposal
Pin the security-critical inputs, keep the benign override:
* {{validateJwtSvid}} uses the *configured* audience only;
{{CamelSpiffeAudience}} is ignored for that operation (and the javadoc/docs say
so). {{fetchJwtSvid}} keeps the header.
* Add an {{allowOperationHeader}} option, default {{false}}, gating
{{CamelSpiffeOperation}}. Existing routes that rely on the header opt in
explicitly.
* Add a Security notes section to {{spiffe-component.adoc}}, mirroring the one
in {{opa-component.adoc}}, recommending {{removeHeaders("CamelSpiffe*")}} on
untrusted ingress.
Tests must cover both directions: the header being ignored where it is pinned,
and still honoured where it is legitimate.
h2. Scope
{{main}} only. {{camel-spiffe}} is new in the unreleased 4.23.0, so no released
version is affected and no security advisory is needed; the
{{allowOperationHeader}} default can be chosen freely.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)