On August 25, 2026, Shopware released version 6.7.13.1. It fixes nine security vulnerabilities (Shopware release notes). According to the advisories, three of them require a malicious or compromised app in the shop: the escape from the App Script sandbox, SQL injection through custom entities and requests into the internal network through addresses an app provides (GitHub advisories, own count). The update closes these holes. It does not answer which apps, integrations and webhooks have access to a shop in the first place, and why. This guide shows how to take inventory of your Shopware shop and cut it back to what is needed: app permissions, webhooks, App Scripts, integrations without an owner and extensions that were only deactivated instead of removed. The focus is security alone; compatibility with the next upgrade is covered in the article on preparing for Shopware 6.8.
What the 2026 security releases reveal about apps
The release notes for 6.7.13.1 sum up the round briefly: eleven fixed issues, nine of them security vulnerabilities and two general bug fixes (Shopware release notes). Reading the advisories linked from the list of fixed bugs, a pattern emerges: three descriptions name the same precondition, a malicious or compromised app (GitHub advisories, own count). On September 16, 2026, 6.7.14.1 followed as a security release (Shopware release notes 6.7.14.1). Among other things, it closed a hole through which webhooks could deliver event data beyond the permissions of their creator (GitHub advisory GHSA-r432-q883-wgvf).
| Advisory | What the hole allowed | Precondition | Rating | Fixed in |
|---|---|---|---|---|
| GHSA-6qhw-38wm-7g7h | Run PHP functions and system commands with the permissions of the web server | Malicious or compromised app, installed and activated | Critical, CVSS 9.6 | 6.6.10.23 and 6.7.13.1 |
| GHSA-xrcf-c96g-q5hr | Run arbitrary SQL through the shop's database connection | Malicious or compromised app with a custom entity | Critical, CVSS 9.1 | 6.6.10.23 and 6.7.13.1 |
| GHSA-rrc3-p9vx-5373 | Make the shop send requests to internal network services via DNS rebinding | Malicious or compromised app | Low, CVSS 3.1 | 6.6.10.23 and 6.7.13.1 |
| GHSA-4wpv-5fvv-c3xp | Assign oneself additional roles up to administrator rights | User with the permission to update users | Moderate, CVSS 6.5 | 6.6.10.23 and 6.7.13.1 |
| GHSA-r432-q883-wgvf | Receive event data beyond one's own permissions through webhooks | User or integration with the permission to create webhooks | Critical, CVSS 9.6 | 6.6.10.25 and 6.7.14.1 |
All holes in the table require an access someone granted in the shop: an installed app, a permission in a role or an integration (GitHub advisories). The update closes the specific hole; how many access points exist for the next one is determined by your own inventory. How the year's security fixes were distributed across the version lines is described in the article on security updates for Shopware 6.5.
The advisories rate according to CVSS 3.1 on a scale from 0 to 10 (GitHub advisory GHSA-6qhw-38wm-7g7h). The score maps to one of four levels from section 5 of the CVSS specification, from low to critical (GitHub Docs). The low rating of the DNS rebinding hole results from its preconditions: according to the vector, an attack needs high privileges and has high complexity (GitHub advisory GHSA-rrc3-p9vx-5373). Fewer apps with far-reaching permissions mean fewer starting points.
Who works in the shop without a user account
In the back end, shop owners mainly see user accounts. Alongside them, components without a face read, write or send data. How roles for people are cut is described in the article on roles and permissions in the shop back end. This article is about the extensions themselves and their technical access.
Apps
An app describes itself in a manifest file and requests permissions there that are confirmed during installation (Shopware Developer Documentation). Its server receives API credentials.
Plugins
Plugins are Symfony bundles, deeply integrated into Shopware; according to the documentation, you can do nearly everything with them (Shopware Developer Documentation). There is no permission manifest.
Integrations
Under Settings > System > Integrations, each connected application gets its own API access, with administrator rights or with a role (Shopware documentation).
Webhooks
A webhook sends a POST request to a stored address when an event occurs (Shopware Developer Documentation). Webhooks come from app manifests or were created through the API.
App Scripts
Twig files of an app that run inside Shopware in a sandbox, for example in the cart (Shopware Developer Documentation).
Custom entities
Apps can define their own data structures. This is where the SQL hole started: Shopware did not sufficiently validate the identifiers in such definitions (GitHub advisory GHSA-xrcf-c96g-q5hr).
For a security review, the difference between app and plugin matters more than for architecture: an app gets an access with defined permissions, a plugin runs as code inside the shop without such a boundary. When which model fits is described in the article Shopware apps vs. plugins. For apps you therefore check permissions, for plugins origin, maintenance and code; how to secure the origin of packages is shown in the article on supply chain attacks on the shop stack.
Step 1: the inventory in one place
The overview under Extensions > My extensions shows the installed extensions and can be limited to active entries (Shopware documentation). Integrations are found elsewhere, under Settings > System > Integrations. Webhooks created through the API do not belong to any extension and do not appear in the extension list. A complete inventory is therefore most reliably built from the database, read on a current copy or with an account that may only read. The tables and columns in the following queries match the entities in Shopware 6.7.15.1 (Shopware source code).
-- Apps with status, version, integration and number of webhooks and scripts
SELECT a.name, a.active, a.version, a.author,
i.admin AS integration_admin, i.last_usage_at,
(SELECT COUNT(*) FROM webhook w WHERE w.app_id = a.id) AS webhooks,
(SELECT COUNT(*) FROM script s WHERE s.app_id = a.id) AS scripts
FROM app a
JOIN integration i ON i.id = a.integration_id
ORDER BY a.active, a.name;
-- Plugins with status, version and available update
SELECT name, active, version, upgrade_version, installed_at
FROM plugin
ORDER BY active, name; The result is a list with one row per component. Three details are not in any table and have to be added in conversation: what the component is for, who in the company or at a service provider is responsible for it and when it was last needed. Rows for which nobody can name a purpose are the actual findings of the review.
- Component and type: app, plugin, integration or webhook without an app
- Status: active, deactivated or uninstalled but still present
- Permissions: permissions requested by the app, role or administrator right of the integration
- Data target: addresses that webhooks and app calls go to
- Responsibility: person or service provider, ideally with a contract
- Last use: last access according to the database or log
Since Shopware 6.7.15.0 of October 1, 2026, the My extensions list can install, activate, deactivate, update or uninstall several entries at once (Shopware release notes 6.7.15.0). The bulk actions respect the same system.plugin_maintain permission as the single actions. This speeds up the cleanup after the review but does not replace the decision per row.
Step 2: hold app permissions against their purpose
Every app that wants to read or write data through the API or receive webhooks must request the necessary permissions in its manifest. A permission combines a privilege, meaning read, create, update or delete, with an entity; since 6.4.12.0, an app can also request privileges beyond these four (Shopware Developer Documentation). The list is confirmed once, during installation.
The permissions you request need to be accepted by the user during the installation of your app. After that, the permissions granted to your app and your API access via the credentials from the confirmation request of the setup workflow are limited to those permissions.
Shopware Developer Documentation, App Registration & Backend Setup
The catch is in the word once: whoever installed an app a while ago agreed to a list nobody remembers today. In addition, read permissions also cover the data in webhooks; an app needs read permissions for the entities of the subscribed events (Shopware Developer Documentation). The yardstick is the purpose. The GDPR requires personal data to be limited to what is necessary in relation to the purposes of processing (GDPR, Art. 5(1)(c)). An app for product reviews needs product data but usually no write access to customer accounts. A newsletter connection needs addresses and consents, not necessarily orders.
-- Permissions per app from the role Shopware created for the app
SELECT a.name, a.active, r.privileges
FROM app a
JOIN acl_role r ON r.id = a.acl_role_id
ORDER BY a.name; - Write and delete on customers and orders where, according to its purpose, the app would only need to read.
- Permissions on users, roles, integrations or webhooks. They allow creating or restructuring further access. The holes GHSA-r432-q883-wgvf and GHSA-4wpv-5fvv-c3xp started exactly at such permissions (GitHub advisories).
- Privileges beyond read, create, update and delete, for example on system functions. The documentation's example is
system:cache:info(Shopware Developer Documentation). - Permissions for functions that are not used in the shop. If an app ships several modules and one of them is not in use, its permissions call for a question to the vendor.
An app's permissions are defined by its manifest. The review therefore ends with one of three decisions: the app keeps its permissions because its purpose justifies them. The vendor is asked for a version with narrower permissions. Or the app is replaced by a solution with narrower access, for example a custom connection through the shop's integrations.
Step 3: webhooks and where the data goes
A webhook is the part of an extension that carries data out of the shop. For every subscribed event, Shopware sends a POST request to the stored address (Shopware Developer Documentation). For write events such as product.written, the payload does not contain complete entities but essentially the identifier of the changed record; other events carry the data that defines the event (Shopware Developer Documentation). Which data actually flows therefore depends on the event.
Webhooks come about in two ways. Apps declare them in their manifest. In addition, users and integrations with the right permission can create webhooks through the API; that is exactly where the hole GHSA-r432-q883-wgvf started (GitHub advisory). For the time until the update, Shopware recommended in the advisory, among other things, restricting the webhook:create permission to trusted administrators and integrations, reviewing existing webhook registrations and removing unexpected entries. This recommendation remains a useful review step beyond the update.
-- All webhooks with target, status, error counter and origin
SELECT w.name, w.event_name, w.url, w.active, w.error_count,
COALESCE(a.name, '(no app)') AS origin
FROM webhook w
LEFT JOIN app a ON a.id = w.app_id
ORDER BY origin, w.event_name; Three columns carry the review. The address shows who receives the data; every host must be attributable to a known service provider or one of your own systems. The event name shows which data flows; events about customers, orders and accounts weigh more than those about products. And the status shows whether the webhook still delivers at all.
If a delivery still fails after the automatic retries, Shopware counts an error; with the default setting, the webhook is switched off at the tenth error (Shopware source code). A webhook whose receiver no longer exists thus drops out of operation by itself. The reverse case is more delicate: the server of a former service provider keeps responding, and the webhook keeps delivering data although nobody needs it anymore.
The delivery logs are part of the review too. Shopware keeps them in the webhook_event_log table with app, event, target address, delivery status and response code (Shopware source code 6.7.15.1). If deliveries to an address nobody can attribute show up there, it is about credentials: the advisory on the webhook hole recommended rotating credentials and account recovery tokens if unauthorized webhook activity is suspected (GitHub advisory GHSA-r432-q883-wgvf).
One special case concerns copies of the shop. If the database is duplicated for a test system, there are two installations with the same shop ID, and apps may receive webhooks from both (Shopware Developer Documentation). Shopware detects this when the APP_URL environment variable changes and stops communicating with the apps until someone decides how to proceed. This safeguard depends on APP_URL actually being changed in the copy. How to set up a test system without real customer data is described in the article on Shopware staging.
If you operate your own receivers, for example for an app that talks to the ERP system, verify the signature on the receiving side: with app webhooks, every request carries a SHA256 HMAC of the request body, created with the secret from the registration (Shopware Developer Documentation). What a robust receiving side with retries and idempotency looks like is shown in the article on webhook architecture.
Step 4: App Scripts and custom entities
Since Shopware 6.4.8.0, apps can bring logic that does not run on their own server but inside the shop (Shopware Developer Documentation). App Scripts are Twig files executed in a sandbox that, depending on the hook, access the data of the respective process and predefined services. Through custom endpoints, scripts can also respond to requests to the Admin API, the Store API or the storefront and have read and write access to the shop's data layer (Shopware Developer Documentation).
The sandbox is the boundary this model relies on. The hole GHSA-6qhw-38wm-7g7h showed what happens when it does not hold: a malicious or compromised app could execute arbitrary PHP functions and operating system commands with the permissions of the web server process, with possible access to configuration and credentials (GitHub advisory). For custom entities, the boundary was the validation of identifiers; a crafted definition could execute arbitrary SQL with the permissions of the database connection (GitHub advisory GHSA-xrcf-c96g-q5hr).
-- Scripts per app and hook
SELECT a.name AS app, s.hook, s.name, s.active
FROM script s
JOIN app a ON a.id = s.app_id
ORDER BY a.name, s.hook;
-- Custom entities and the app that defines them
SELECT c.name, a.name AS app
FROM custom_entity c
JOIN app a ON a.id = c.app_id
ORDER BY a.name; For the inventory, this leads to a distinction that is not visible in the extension list: apps that only work through their own server and the API, and apps that bring code or definitions into the shop. For the second group, origin matters more. The advisories say the same: install and update apps only from trusted sources and review installed apps, particularly those that define custom entities (GitHub advisory GHSA-xrcf-c96g-q5hr). Scripts with endpoints in the Store API are aimed at front ends and therefore reachable from outside; how to secure this interface is described in the article securing the Store API.
Step 5: integrations without an owner
Integrations are the shop's API access points. Under Settings > System > Integrations, you can create a separate access for each of your own applications, with administrator permissions or with a role; the secret access key is only shown when it is created (Shopware documentation). Every app is linked to an integration as well, and apps with their own server receive its credentials during registration (Shopware Developer Documentation).
Orphaned integrations are those whose reason has passed: the access for a migration, the connection of an ERP system that has since been replaced, a test access of a former agency. They do not stand out because they do nothing, and they remain a risk because their key is still valid. OWASP describes this situation as improper inventory management: without an inventory and a retirement plan, systems keep running unmaintained, and data can leak through third parties with whom there is no longer any reason to share data (OWASP API Security Top 10 2023).
-- Integrations without an app, with admin flag and last use
SELECT i.label, i.admin, i.last_usage_at, i.created_at
FROM integration i
LEFT JOIN app a ON a.integration_id = i.id
WHERE a.id IS NULL AND i.deleted_at IS NULL
ORDER BY i.last_usage_at; Shopware stores the time of last use for every integration (Shopware source code 6.7.15.1). An integration that has not been used for a long time and for which nobody can name a purpose is deleted. An integration with administrator rights whose application only syncs stock and order status gets a role with exactly these permissions instead. And where it is unclear who knows the key, regenerating helps: it renews the access ID and the secret access key at the same time (Shopware documentation). The application that is meant to keep working gets the new credentials, all others lose access.
Integrations also concern processes that do not look technical. If you automatically hand over customer lists to an advertising platform, as described in the article on new and returning customers in Google Ads, you operate a data flow with personal data that belongs in the inventory with its purpose and owner.
Step 6: deactivated is not removed
Deactivating is convenient because it breaks nothing: unlike uninstalling, deactivating keeps an app's settings, and an uninstalled app remains in the overview until it is removed (Shopware documentation). For the security review this means: code and settings remain in the shop, possibly including credentials for third-party services from the configuration. Anyone with the permission to manage extensions can switch the old state back on with one click.
On top of that, deactivated extensions easily drop out of maintenance: whoever only maintains what runs lets the switched-off entries age unnoticed. One example is the former payment app after a change of provider; how to test payment flows before and after a change is shown in the article on failed payments. The only question here is whether the extension is still needed.
| Decision | When | What to do |
|---|---|---|
| Reactivate | The function is needed | Install updates, review permissions and webhooks as for active apps, assign responsibility |
| Uninstall with data | The function is no longer needed | Back up data subject to retention, uninstall and permanently remove the app data |
| Remove | The extension is already uninstalled | Remove from the overview, for plugins also from Composer or the plugin directory |
| Keep for now | Fallback during an ongoing switch | Set an end date and note it in the inventory |
Legal framework: data minimization and regular review
The review is not only technology. Among other things, the GDPR requires controllers to implement security measures that include, as appropriate, a process for regularly testing, assessing and evaluating their effectiveness (GDPR, Art. 32(1)(d)). A dated inventory of access points with findings and decisions is an obvious building block for this evidence.
a process for regularly testing, assessing and evaluating the effectiveness of technical and organisational measures for ensuring the security of the processing.
General Data Protection Regulation, Art. 32(1)(d)
If an app transfers personal data to its vendor's server so that the vendor processes it on behalf of the shop, the vendor is usually a processor. The shop may then only use processors that offer sufficient assurance of appropriate technical and organizational measures (GDPR, Art. 28(1)). For the inventory, this means one more column: is there a data processing agreement for this app? Whether that applies in an individual case is for the data protection officer or legal counsel to decide, not for the technology.
Review cycle: when the inventory is due
An inventory becomes outdated with every installation. A fixed date makes sense, plus occasions that trigger an extra review.
- After every security release that concerns apps, webhooks or permissions. The release notes list the advisories with short titles; keywords such as app, webhook, ACL or integration are the trigger (Shopware release notes).
- When changing a service provider or a connected software. The old access is deleted as soon as the new one runs, not at some point later.
- Before copying the shop for testing or acceptance, so that the copy does not send webhooks to production systems.
- When a person with administrator rights leaves, because they may have created integrations and webhooks.
- As a fixed date, usually once a quarter, even if none of the occasions has occurred.
The first inventory takes longest because purposes and responsibilities have to be clarified first. Every further round compares against the last state: what is new, what has gone, whose purpose has ended.
How we support the extension inventory
We take the inventory of your shop from the database and the administration and compare it with you against the actual processes. For each row there is a proposal: keep, ask the vendor, replace with a narrower connection or remove. Changes are made in a test environment first. As part of Shopware maintenance, we repeat the review at fixed intervals and after security releases if agreed.
Inventory and findings
Apps, plugins, integrations, webhooks and App Scripts in one list, with permissions, data targets, last use and a recommendation per row.
Narrower connections
If an app needs more permissions than its purpose justifies, we can develop a custom connection with exactly the necessary permissions, as an app or plugin from our programming team.
Outbound connections
The advisory on the DNS rebinding hole names restricting outbound connections to the destinations of trusted apps as a workaround (GitHub advisory GHSA-rrc3-p9vx-5373). What is possible here, we clarify with you as part of Shopware hosting.
Every access needs a purpose and an owner
The security releases of 2026 have shown that holes in the app system, in webhooks and in roles are not edge cases. Updates remain the first answer. The second is a shop in which every app, every integration and every webhook has a purpose and a responsible person, and everything else is removed. Once you have recorded that, every further round only needs a comparison with the last state.
This article is based on Shopware's release notes for 6.7.13.1, 6.7.14.1 and 6.7.15.0, Shopware's security advisories on GitHub (for our own count, all advisories linked from the 6.7.13.1 release notes), the Shopware Developer Documentation, the Shopware user documentation, the Shopware source code in version 6.7.15.1, GitHub's documentation of its advisory database, the OWASP API Security Top 10 2023 and the General Data Protection Regulation (Art. 5, 28 and 32). All sources accessed on October 30, 2026.
Updates close known holes and are the first measure. But they do not change which apps, integrations and webhooks have access, and several holes in 2026 required exactly such an access (GitHub advisories). An inventory reduces the places where a future hole can start.
Compare the requested permissions with the purpose of the app. Write and delete permissions on customers or orders, permissions on users, roles, integrations or webhooks and permissions for unused functions usually call for a question to the vendor. The permissions are stored in the role Shopware creates for each app.
They remain in the shop with code and settings and can be switched back on by anyone with the permission to manage extensions, often without anyone updating them first. If an extension is no longer needed, uninstalling and removing the app data is usually the cleaner way (Shopware documentation).
In the webhook table of the shop database they have no reference to an app, and they can also be retrieved through the Admin API. Every target address should be attributable to a known receiver. Shopware recommended removing unexpected entries in the advisory on the webhook hole (GitHub advisory GHSA-r432-q883-wgvf).
First check the last use that Shopware stores per integration; if it is no longer used, delete it. If an application might still depend on it, regenerate the keys and give them only to the applications that are meant to keep running. Whatever reports errors afterwards was the unknown dependency.
Usually a fixed date once a quarter is enough, plus a review after security releases concerning apps, webhooks or permissions, after a change of service provider and before copying the shop. As part of Shopware maintenance, we take care of this on request.