Skip to content

GHSA-5974-gfqc-wrcm CVE-2026-107851

Contao: Improper access control in the table access voter

Medium Packagist
Severity
4.3 / 10
Medium · CVSS 3.1
Exploit chance (EPSS)
0.19%
Chance of exploitation in the next 30 days. Higher than 9.03% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-524 Use of Cache Containing Sensitive Information
CWE-863 Incorrect Authorization
Fix
5.7.12
Upgrade contao/core-bundle to this version or later

Description

Due to a caching defect in the security voter that governs table-level access to Contao's Data Container (DCA) backend, a low-privileged, non-admin backend user can obtain unauthorized read, create, update, and delete access to database tables outside their assigned module permissions. This includes tables containing sensitive personal data, such as frontend member records and newsletter subscriber e-mail addresses.

Vulnerability Details

In plain terms: Contao's backend is organized into modules (e.g. "News", "Members"). Every backend user is assigned to a group, and that group decides which modules, and therefore which database tables, they are allowed to work with. Before Contao lets a user touch a table, it is supposed to check: "does this user's group actually include this table?"

To avoid doing that check over and over, Contao remembers the answer for the rest of the request. The problem is that it remembers the answer under the wrong label. Instead of remembering "is this user allowed to access table X", it only remembers "is this user allowed to access something", without recording which table the answer was actually about.

So if a request first checks a table the user IS allowed to see, and then checks a second, completely different table the user is NOT allowed to see, Contao reuses the first answer for the second table too. The user ends up with access to a table their group was never given permission for.

Technical detail

Contao's backend enforces per-table access control through a chain of Symfony security voters. The relevant one is TableAccessVoter::hasAccessToModule(), in core-bundle/src/Security/Voter/DataContainer/TableAccessVoter.php:

    private array $canAccessTable = [];
    private array $canReadAccessTable = [];
 
    private function hasAccessToModule(TokenInterface $token, ...): bool
    {
        $tokenHash = hash('xxh128', serialize($token));
 
        if (isset($this->canAccessTable[$tokenHash]) || (...)) {
            return $this->canAccessTable[$tokenHash] ?? $this->canReadAccessTable[$tokenHash];
        }
 
        $table = $subject->getDataSource();
 
        foreach ($GLOBALS['BE_MOD'] as $modules) {
            ...
            return $this->canAccessTable[$tokenHash] = true;  // or false
        }
    }

The cache key, $tokenHash, is built only from the current user's security token. It does not include the table being checked. Because TableAccessVoter is a normal, shared Symfony service, this cache stays alive for the whole duration of one HTTP request. So the first table checked for a user in a request decides the cached answer for every other table checked afterwards in that same request, whether or not that answer is actually correct for the second table.

This is made worse by DefaultDataContainerVoter, a low-priority, permissive fallback voter that grants access to any table-related permission unless another voter explicitly denies it. When TableAccessVoter gives a wrong "no opinion" answer because of the stale cache, this fallback voter turns that into a full grant.

Most database tables in Contao have no second, table-specific check to catch this. Only tl_content, tl_favorites, tl_form, tl_form_field, tl_module, tl_image_size(_item), tl_job, tl_layout, tl_page, tl_preview_link, tl_undo, and tl_user have one. Tables such as tl_member (website member data), tl_newsletter_recipients (subscriber e-mail addresses), tl_news, tl_calendar_events, tl_faq, and tl_comments rely only on the defective check described above.

Credits

This security vulnerability was found by Sven Jäger of SySS GmbH.

Affected versions

Packagist

PackageVulnerableFixed in
contao/core-bundle
>= 5.7.0, < 5.7.12
5.7.12

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

contao/core-bundle Packagist → 5.7.12

composer
composer require contao/core-bundle:^5.7.12

Severity breakdown

CVSS 3.1 4.3

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

Weakness

CWE-524: Use of Cache Containing Sensitive Information

The code uses a cache that contains sensitive information, but the cache can be read by an actor outside of the intended control sphere.

How to prevent it
  • Architecture and Design: Protect information stored in cache.
  • Architecture and Design: Do not store unnecessarily sensitive information in the cache.
  • Architecture and Design: Consider using encryption in the cache.

CWE-863: Incorrect Authorization

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.

How to prevent it
  • Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
  • Architecture and Design: Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
  • Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
  • Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
  • System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-9ff2-p842-45wq
Contao: Cross-site request forgery in custom backend actions
Low Also affects contao/core-bundle
GHSA-q6wp-fr43-gm9v
Contao: Improper access control in the preview links module
Medium Also affects contao/core-bundle
GHSA-mrvp-7wmx-5m4h
Contao: Path traversal in the images controller
Medium Also affects contao/core-bundle
GHSA-mfxh-vp55-7gc6
Contao: The registration module re-sends activation mails
Medium Also affects contao/core-bundle
GHSA-x2rp-9qf7-2fmq
Contao: Protected page content is disclosed to anonymous visitors after contao.search.index_protected is disabled
Medium Also affects contao/core-bundle
GHSA-grm4-wm43-9jh5
Contao: Possible path traversal in job download URIs
Low Also affects contao/core-bundle
GHSA-87mg-5grr-rhwh
Contao: Server-Side Request Forgery (SSRF) via Unvalidated RSS Feed URL in Feed Reader Module
Low Also affects contao/core-bundle
GHSA-3mr9-p497-58f6
Contao crawler leaks auth credentials to external hosts
Low Also affects contao/core-bundle
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor