Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
# for local docker dev
docker
.env

.composer/
Binary file modified .wordpress-org/screenshot-11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .wordpress-org/screenshot-6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .wordpress-org/screenshot-7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .wordpress-org/screenshot-8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"PKSA-1tmc-rt7x-12w6": "CVE-2026-48806 (sandbox `__toString()` bypass via dynamic mapping keys): not exploitable - Matomo does not enable Twig's sandbox. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-21g2-dzjv-sky5": "CVE-2026-46634 (`template_from_string()` escapes a SourcePolicy-driven sandbox): not exploitable - Matomo does not call `template_from_string`\/`createTemplate` at runtime (only one TagManager test fixture) and does not implement `SourcePolicyInterface`. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-3mcc-k66d-pydb": "CVE-2026-46638 (`{% sandbox %}{% include %}` skips `checkSecurity()` on cached templates): not exploitable - Matomo uses neither the `{% sandbox %}` tag nor `SandboxExtension`. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-8zx5-v2nz-58pb": "CVE-2026-49981 (sandbox filter, tag and function allow-list bypass when sandbox state changes between renders for a cached `Template`): not exploitable - Matomo does not enable Twig's sandbox or toggle sandbox state. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-dpx1-78wg-1kqs": "CVE-2026-47732 (multiple sandbox `__toString()` bypasses via unguarded string coercion points): not exploitable - Matomo does not enable Twig's sandbox. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-fbvq-z33h-r2np": "CVE-2026-48808 (sandbox property allowlist bypass via `column` filter under `SourcePolicyInterface`): not exploitable - Matomo does not register `SandboxExtension` or implement `SourcePolicyInterface`. Upgrade blocked while Matomo supports PHP 7.2.",
"PKSA-g9zw-qxh8-pq8w": "CVE-2026-48805 (sandbox state regression in deprecated wrappers in `vendor\/twig\/twig\/src\/Resources\/core.php`): not exploitable - Matomo does not enable Twig's sandbox. Upgrade blocked while Matomo supports PHP 7.2.",
Expand Down
92 changes: 38 additions & 54 deletions app/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion app/config/global.ini.php
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,13 @@
; If you may need to download GeoIP updates or other stuff using other protocols like ftp you may need to extend this list.
allowed_outgoing_protocols = 'http,https'

; HTTP requests fetching a user-configured URL (e.g. a site's URL for site content detection) refuse to
; contact private, loopback or otherwise reserved IP addresses, so they cannot be pointed at other servers
; in this Matomo's network. If this Matomo tracks intranet sites hosted on such addresses, allowlist their
; ranges here. Accepts single IPs, CIDR notation and wildcards, both IPv4 and IPv6.
; allowed_private_egress_ranges[] = "10.0.0.0/8"
; allowed_private_egress_ranges[] = "192.168.1.*"

; This option forces matomo marketplace and matomo api requests to use HTTP, as default we use HTTPS to improve security
; If you have a problem loading the marketplace, please enable this config option
force_matomo_http_request = 0
Expand Down Expand Up @@ -1028,7 +1035,7 @@

; Comma separated list of URL query string variable names that will be removed from your tracked URLs
; By default, Matomo will remove the most common parameters which are known to change often (eg. session ID parameters)
url_query_parameter_to_exclude_from_url = "gclid,fbclid,msclkid,twclid,wbraid,gbraid,yclid,fb_xd_fragment,fb_comment_id,phpsessid,jsessionid,sessionid,aspsessionid,doing_wp_cron,sid,pk_vid,li_fat_id"
url_query_parameter_to_exclude_from_url = "gclid,fbclid,msclkid,twclid,wbraid,gbraid,yclid,fb_xd_fragment,fb_comment_id,phpsessid,jsessionid,sessionid,aspsessionid,doing_wp_cron,sid,pk_vid,li_fat_id,token_auth,token"

; If set to 1, Matomo will use the default provider if no other provider is configured.
; In addition the default provider will be used as a fallback when the configure provider does not return any results.
Expand Down Expand Up @@ -1337,6 +1344,7 @@
Plugins[] = FeatureFlags
Plugins[] = AIAgents
Plugins[] = BotTracking
Plugins[] = AIProviders

[PluginsInstalled]
PluginsInstalled[] = Diagnostics
Expand Down
42 changes: 42 additions & 0 deletions app/core/API/DataTableGenericFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
use Piwik\Plugin\Report;
class DataTableGenericFilter
{
/**
* The generic filters that reduce the result to the requested page of rows instead of
* removing rows that do not match the request.
*
* @var string[]
*/
private const ROW_LIMITING_FILTERS = array('Truncate', 'Limit');
/**
* List of filter names not to run.
*
Expand All @@ -29,6 +36,10 @@ class DataTableGenericFilter
* @var array
*/
private $request;
/**
* @var callable|null
*/
private $callbackBeforeRowLimitingFilters;
/**
* @param array $request
* @param Report $report
Expand All @@ -38,6 +49,23 @@ public function __construct($request, $report)
$this->request = $request;
$this->report = $report;
}
/**
* Sets a callback that is invoked with every filtered DataTable after the filters that remove
* and sort rows have been applied, but before the row limiting filters reduce the table to the
* requested page of rows.
*
* At that point the table contains every row matching the request, which makes it the place to
* compute values that have to take all matching rows into account.
*
* The callback is invoked exactly once per DataTable, even when all row limiting filters are
* disabled or skipped.
*
* @param callable|null $callback A callback that receives the DataTable being filtered.
*/
public function setCallbackBeforeRowLimitingFilters(?callable $callback) : void
{
$this->callbackBeforeRowLimitingFilters = $callback;
}
/**
* Filters the given data table
*
Expand Down Expand Up @@ -108,11 +136,16 @@ protected function applyGenericFilters($datatable)
$tableDisabledFilters = $datatable->getMetadata(DataTable::GENERIC_FILTERS_TO_DISABLE_METADATA_NAME) ?: [];
$genericFilters = $this->getGenericFiltersHavingDefaultValues();
$filterApplied = \false;
$rowLimitingFiltersReached = \false;
foreach ($genericFilters as $filterMeta) {
$filterName = $filterMeta[0];
$filterParams = $filterMeta[1];
$filterParameters = array();
$exceptionRaised = \false;
if (!$rowLimitingFiltersReached && in_array($filterName, self::ROW_LIMITING_FILTERS, \true)) {
$rowLimitingFiltersReached = \true;
$this->invokeCallbackBeforeRowLimitingFilters($datatable);
}
if (in_array($filterName, $this->disabledFilters) || in_array($filterName, $tableDisabledFilters)) {
continue;
}
Expand Down Expand Up @@ -143,8 +176,17 @@ protected function applyGenericFilters($datatable)
$filterApplied = \true;
}
}
if (!$rowLimitingFiltersReached) {
$this->invokeCallbackBeforeRowLimitingFilters($datatable);
}
return $filterApplied;
}
private function invokeCallbackBeforeRowLimitingFilters(DataTable $datatable) : void
{
if (null !== $this->callbackBeforeRowLimitingFilters) {
call_user_func($this->callbackBeforeRowLimitingFilters, $datatable);
}
}
public function areProcessedMetricsNeededFor($metrics)
{
$columnQueryParameters = array('filter_column', 'filter_column_recursive', 'filter_excludelowpop', 'filter_sort_column');
Expand Down
7 changes: 6 additions & 1 deletion app/core/API/DataTableManipulator/Flattener.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,19 @@ private function flattenRow(Row $row, $rowId, DataTable $dataTable, $level, $dim
}
}
/**
* Remove the flat parameter from the subtable request
* Remove the flat & filter_pattern parameters from the subtable request
*
* @param array $request
* @return array
*/
protected function manipulateSubtableRequest($request)
{
unset($request['flat']);
// don't apply the search pattern while subtables are loaded, otherwise rows are filtered on
// their child label before the parent label parts are combined into the final flattened label.
// that would drop rows whose match only appears in a parent label. instead we let the pattern
// run once on the flattened table (via the generic filters applied after flattening).
unset($request['filter_pattern']);
return $request;
}
}
Loading
Loading