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)

Reply via email to