Oct 10, 2026·5 min read·8 visits
Unauthenticated path traversal in Contao ImagesController permits arbitrary reading of localized files matching allowed extensions and system directory probing.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
A path traversal vulnerability exists within the dynamic image processing sub-system of Contao CMS. The flaw is located in the ImagesController component (core-bundle/src/Controller/ImagesController.php), which processes image resizing and serving requests derived from URL parameters.
When a request targets an image asset, ImagesController resolves the user-supplied {path} route parameter against a designated image target directory. Because the component fails to enforce directory boundary checks on the resolved path, relative directory traversal sequences allow the canonical path to reference locations higher up in the application filesystem hierarchy.
This vulnerability is accessible to unauthenticated remote attackers over HTTP or HTTPS endpoints handling image transformations. Although file retrieval is limited to file extensions allowed by the system configuration, an attacker can enumerate local files, verify filesystem structures, or trigger verbose debug errors that reveal absolute filesystem paths.
The underlying security weakness stems from an inadequate validation step prior to instantiating image processing objects. In affected Contao releases, ImagesController utilizes the Symfony Path::join() utility to combine the base target directory ($this->targetDir) with the client-provided path parameter ($path).
While Path::join() normalizes dot segments such as . and .., it does not restrict the canonicalized output path to the base directory prefix. As a result, if $path contains parent directory traversals like ../.., Path::join() produces an absolute path outside the intended target directory scope.
Because the controller previously passed this path directly into $this->imageFactory->create(), the system attempted to access and process the target file without validating ownership or location relative to $this->targetDir. The missing safeguard is the invocation of Path::isBasePath($this->targetDir, $path), which verifies that the resolved path resides strictly within the target base path.
Analysis of the vulnerable implementation in core-bundle/src/Controller/ImagesController.php shows that the path parameter was joined inline during factory creation:
// Vulnerable code in core-bundle/src/Controller/ImagesController.php
public function __invoke(string $path): Response
{
try {
try {
// Path::join resolves '..' but does not restrict output to $this->targetDir
$image = $this->imageFactory->create(Path::join($this->targetDir, $path));
} catch (\InvalidArgumentException $exception) {
throw new NotFoundHttpException($exception->getMessage(), $exception);
}The security patch introduced in commit 867c055122fdf12220f973f862082037b695b9bd resolves the target path prior to processing and enforces explicit boundary checking via Path::isBasePath():
// Patched code in core-bundle/src/Controller/ImagesController.php
public function __invoke(string $path): Response
{
// Step 1: Pre-join and normalize the path
$path = Path::join($this->targetDir, $path);
// Step 2: Validate that the resolved path stays within $this->targetDir
if (!Path::isBasePath($this->targetDir, $path)) {
throw new NotFoundHttpException('Image does not exist');
}
try {
try {
// Step 3: Pass normalized, validated path to the image factory
$image = $this->imageFactory->create($path);
} catch (\InvalidArgumentException $exception) {
throw new NotFoundHttpException($exception->getMessage(), $exception);
}Unit tests were added in core-bundle/tests/Controller/ImagesControllerTest.php to confirm that passing ../dummy.jpg triggers a NotFoundHttpException without invoking ImageFactoryInterface::create().
An attack against CVE-2026-107844 involves sending a crafted HTTP GET request to routes managed by ImagesController. Prerequisites for exploitation include network access to the application endpoints and knowledge of target paths relative to the image storage location.
An attacker supplies path traversal payloads embedded in the route parameter, such as /assets/images/../../system/config/config.png. If the requested file exists and its extension matches allowed entries in contao.image.valid_extensions, the controller processes the file and returns it inside a Symfony BinaryFileResponse object.
If the target file extension is not permitted, the system returns an error response; however, distinct response codes and execution timings allow attackers to differentiate between existing files, missing files, and unpermitted file formats. In environments where application debug features are active, detailed error stacks return absolute system filesystem paths.
The CVSS v3.1 base score for CVE-2026-107844 is evaluated at 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N). The vulnerability exhibits high exploitability due to its unauthenticated remote nature and low attack complexity.
Impact is constrained primarily to Confidentiality (C:L). An attacker cannot modify files (I:N) or trigger denial of service conditions directly (A:N). Furthermore, scope remains unchanged (S:U) because traversal cannot breach host kernel boundaries or container isolates beyond web server process permissions.
Threat classification aligns with MITRE ATT&CK techniques T1083 (File and Directory Discovery) and T1005 (Data from Local System). While EPSS metrics place likelihood of automated exploitation at a low baseline, exposure risks remain elevated for deployments disclosing debug information.
Remediation requires updating the contao/contao dependency to a patched version. Environments running Contao 5.3.x must update to 5.3.50 or higher, and environments running Contao 5.7.x must update to 5.7.12 or higher.
Execute the following Composer command in the project root directory to retrieve updated package dependencies:
composer update contao/contao --with-dependenciesFor environments where immediate maintenance updates cannot be performed, Web Application Firewall (WAF) filtering rules should be deployed to detect and block URL-encoded traversal sequences such as %2e%2e%2f, %2e%2e/, and ..%2f within target image routing URIs.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Contao CMS Contao | >= 5.0.0, < 5.3.50 | 5.3.50 |
Contao CMS Contao | >= 5.4.0-RC1, < 5.7.12 | 5.7.12 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) |
| CVSS v3.1 Score | 5.3 (Medium) |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N |
| Attack Vector | Network (Unauthenticated HTTP/HTTPS GET requests) |
| EPSS Score | 0.00312 (22.18th percentile) |
| Impact | Partial Information Disclosure / Local File Enumeration |
| Exploit Status | Proof of Concept / Public Commit Diffs Available |
| CISA KEV Status | Not Listed |
The software uses external input to construct a pathname that should be restricted to a directory within a restricted parent directory, but does not properly neutralize special elements such as '..' sequences.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.
An information disclosure vulnerability in Vikunja allows authenticated users with read access to a task to expose private email addresses of assigned users through the API task assignees endpoint due to an unmasked database query.