
Runnable proof-of-concept reproducer for CVE-2026-79983, a path traversal in Apache Camel camel-ftp consumers, with malicious FTP server fixtures and affected vs fixed builds.
Runnable proof-of-concept reproducer for the Apache Camel vulnerability where the remote-file consumers poll a
directory on a remote server and build the absolute remote path of each file by concatenating the configured
directory with the file name reported in the server's directory listing, with no lexical normalization and no
check that the result stays inside the polled directory. That path then becomes the operand for retrieval (always),
and for deletion or rename when delete=true, move, preMove, moveFailed or readLock=rename is configured.
A listing name is not route-controlled data — it is supplied by the remote server, and the FTP control channel
has no integrity protection, so an on-path attacker can rewrite a LIST response, and a compromised or multi-tenant
server can emit such a name directly. The documented, default-on jailStartingDirectory option did not constrain
this remote operand.
| Runtime | Directory | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-ftp 4.22.0 (affected; fixed 4.22.1) |
| Camel Quarkus | camel-quarkus/ | Quarkus 3.29.0 + camel-quarkus-ftp 3.29.0 (Camel 4.15.0, affected) |
The fix ships in Camel 4.18.5 / 4.22.1 / 4.23.0; the Spring Boot module runs both the affected build (4.22.0) and the fixed build (4.22.1). No released Camel Quarkus yet bundles a fixed Camel.
The app embeds a deliberately malicious FTP server (Apache MINA FtpServer with an in-memory VFS) that lists, in
the polled directory /upload:
normal.txt — a legitimate file inside the directory, andd/../../outside.txt — a crafted entry whose name is not a single path segment. It does not start with a dot
(so Camel's hidden-file rule does not catch it), and /upload + d/../../outside.txt resolves to /outside.txt,
one level above the polled directory.A plain Camel FTP consumer polls /upload. On the affected build it retrieves both entries — including
/outside.txt, a file it should never reach. On the fixed build it keeps normal.txt and skips the escaping
entry, logging Skipping file as it resolves outside the starting directory: upload/d/../../outside.txt.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Expected output on the affected build:
What the Camel consumer retrieved:
name=[normal.txt] (inside)
name=[d/../../outside.txt] <<< FILE FROM OUTSIDE THE POLLED DIRECTORY
content: OUTSIDE-SECRET (/outside.txt, a file the consumer should never reach)
Paths the server was asked to read:
upload/normal.txt -> /upload/normal.txt
upload/d/../../outside.txt -> /outside.txt
| Property | Value |
|---|---|
| Component | camel-ftp (ftp, ftps, sftp schemes) |
| CWE | CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) |
| Severity | HIGH |
| Attack vector | A LIST entry (server-supplied, rewritable on an unauthenticated FTP control channel) that is not a single path segment |
| Impact | Read — and, with delete/move/readLock=rename, delete or rename — files outside the polled directory, using the endpoint's credentials |
| Affected Versions | From 4.0.0 before 4.18.5, from 4.19.0 before 4.22.1 |
| Fixed Versions | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24487 |
| Credit | Dilrevx from NSSL, SJTU |
Advisory: https://camel.apache.org/security/CVE-2026-79983.html
A separator-aware GenericFileHelper.isWithinDirectory overload and a GenericFileConsumer.isWithinStartingDirectory
strategy (consulted from isValidFile when jailStartingDirectory is enabled) compact the resolved path and verify,
on path-segment boundaries, that it still resolves inside the polled directory. A file resolving outside is skipped
with a warning (so other legitimate entries in the same listing still process). RemoteFileConsumer and
SmbConsumer override the check; the local base implementation is a no-op, since local listing names are always
single segments.
Prefer sftp/ftps over ftp so the listing cannot be rewritten in transit, and verify the host key/certificate.
Constrain the consumer with filter, antInclude or include to accept only single-segment names, and avoid
delete=true/move/preMove/moveFailed/readLock=rename against servers whose listings are not fully trusted.
Where possible, confine the server account to the polled directory.
This repository is published for educational and defensive purposes: to help Apache Camel users understand the vulnerability, verify whether they are affected, and confirm that upgrading resolves it. The malicious server and the "secret" are inert local fixtures. Do not use this material against systems you do not own or operate.