diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml
index c58ebd05..934a65ce 100644
--- a/.mokogitea/workflows/issue-branch.yml
+++ b/.mokogitea/workflows/issue-branch.yml
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: MokoGitea.Workflow
# INGROUP: mokocli.Automation
-# VERSION: 02.58.35
+# VERSION: 02.58.36
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
diff --git a/SECURITY.md b/SECURITY.md
index 345d2cb3..73a6d6e9 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla
INGROUP: Template-Joomla.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
PATH: /SECURITY.md
-VERSION: 02.58.35
+VERSION: 02.58.36
BRIEF: Security vulnerability reporting and handling policy
-->
diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml
index 187ea632..61d533d3 100644
--- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml
@@ -17,7 +17,7 @@
display label there.
-->
MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql
new file mode 100644
index 00000000..bd262657
--- /dev/null
+++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.58.36.sql
@@ -0,0 +1 @@
+/* 02.58.36 — no schema changes */
diff --git a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php
index 9e32577a..3b59ccf0 100644
--- a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php
+++ b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php
@@ -125,11 +125,23 @@ class SnapshotRestoreEngine
$prefix = $db->getPrefix();
$totalRows = 0;
- try {
- $db->transactionStart();
+ // Build list of tables to restore based on selected types
+ $tablesToRestore = $this->getTablesToRestore($restoreTypes);
- // Build list of tables to restore based on selected types
- $tablesToRestore = $this->getTablesToRestore($restoreTypes);
+ /* Duplicate mode inserts brand-new records through Joomla's Table API,
+ whose Nested tables (categories, tags) issue LOCK TABLES — which
+ implicitly COMMITS any open transaction in MySQL/InnoDB. Wrapping it
+ in transactionStart()/Rollback() would be a false atomicity promise:
+ the first category/tag store would commit and defeat the rollback.
+ Duplicate mode is therefore best-effort and per-item defensive (a bad
+ item is skipped and logged, never fatal) rather than all-or-nothing.
+ The raw-DB modes (replace/create/merge) remain fully transactional. */
+ $useTransaction = ($mode !== 'duplicate');
+
+ try {
+ if ($useTransaction) {
+ $db->transactionStart();
+ }
if ($mode === 'duplicate') {
$totalRows = $this->restoreDuplicate($data, $restoreTypes);
@@ -156,7 +168,9 @@ class SnapshotRestoreEngine
}
}
- $db->transactionCommit();
+ if ($useTransaction) {
+ $db->transactionCommit();
+ }
$this->log('Restore complete: ' . $totalRows . ' total rows');
@@ -188,11 +202,15 @@ class SnapshotRestoreEngine
'log' => implode("\n", $this->log),
];
} catch (\Throwable $e) {
- try {
- $db->transactionRollback();
- $this->log('Transaction rolled back');
- } catch (\Exception $rollbackEx) {
- $this->log('Rollback failed: ' . $rollbackEx->getMessage());
+ if ($useTransaction) {
+ try {
+ $db->transactionRollback();
+ $this->log('Transaction rolled back');
+ } catch (\Exception $rollbackEx) {
+ $this->log('Rollback failed: ' . $rollbackEx->getMessage());
+ }
+ } else {
+ $this->log('Duplicate mode is not transactional; records already inserted are left in place.');
}
$this->log('FATAL: ' . $e->getMessage());
diff --git a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php
index 5e148445..5f408e55 100644
--- a/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php
+++ b/source/packages/com_mokosuitebackup/tmpl/runbackup/default.php
@@ -34,6 +34,14 @@ if ($this->returnUrl !== '') {
$decoded = base64_decode($this->returnUrl, true);
$raw = ($decoded !== false && $decoded !== '') ? $decoded : $this->returnUrl;
+ /* Reject any backslash or control char outright: legitimate Joomla admin
+ return URLs never contain them, and a browser normalises a leading "/\"
+ to "//", turning a would-be root-relative path into a protocol-relative
+ open redirect (e.g. "/\evil.com" → "//evil.com"). */
+ if (preg_match('/[\x00-\x1f\x7f\\\\]/', $raw)) {
+ $raw = '';
+ }
+
$isAbsoluteHttp = (bool) preg_match('#^https?://#i', $raw);
$isRootRelative = isset($raw[0]) && $raw[0] === '/' && (!isset($raw[1]) || $raw[1] !== '/');
diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml
index 4f635e5c..e9756fec 100644
--- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml
+++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml
@@ -8,7 +8,7 @@
-->
Module - MokoSuiteBackup - cPanel
- 02.58.35
+ 02.58.36
2026-06-23
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml
index 3bc177fb..dd9ca3e9 100644
--- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
Action Log - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-04
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml
index 45e20e18..951da50a 100644
--- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
Console - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-04
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml
index 578c792f..3d0f5112 100644
--- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
Content - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-04
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml
index 53de7146..3ee21949 100644
--- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml
@@ -1,7 +1,7 @@
Quick Icon - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js
index 6f80f850..477df90e 100644
--- a/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js
+++ b/source/packages/plg_system_mokosuitebackup/media/js/installer-backup.js
@@ -70,6 +70,22 @@
return;
}
+ var ret = window.location.href;
+ ret += (ret.indexOf('?') === -1 ? '?' : '&') + 'msb_resume=1';
+
+ /* Build the redirect BEFORE we swallow the click. btoa() throws on
+ non-Latin1 input (e.g. a UTF-8 filter value in the query string), so
+ encode as UTF-8 first; if it still fails, bail WITHOUT preventing the
+ click so Joomla's own update/uninstall proceeds normally. */
+ var target;
+ try {
+ target = cfg.runbackupUrl
+ + '&profile_id=' + encodeURIComponent(cfg.profileId)
+ + '&returnurl=' + encodeURIComponent(btoa(unescape(encodeURIComponent(ret))));
+ } catch (x) {
+ return;
+ }
+
e.preventDefault();
e.stopImmediatePropagation();
@@ -77,12 +93,7 @@
sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ task: task, cids: cids }));
} catch (x) {}
- var ret = window.location.href;
- ret += (ret.indexOf('?') === -1 ? '?' : '&') + 'msb_resume=1';
-
- window.location.href = cfg.runbackupUrl
- + '&profile_id=' + encodeURIComponent(cfg.profileId)
- + '&returnurl=' + encodeURIComponent(btoa(ret));
+ window.location.href = target;
}, true);
/* On return from the backup screen: restore the selection and re-fire. */
diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml
index fb2f9f37..53e6e4fa 100644
--- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
System - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml
index 46dd12db..670652f3 100644
--- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
Task - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml
index 8cdaf10f..86609f71 100644
--- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml
+++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml
@@ -7,7 +7,7 @@
-->
Web Services - MokoSuiteBackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech
diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml
index 9690b40c..b175f745 100644
--- a/source/pkg_mokosuitebackup.xml
+++ b/source/pkg_mokosuitebackup.xml
@@ -8,7 +8,7 @@
Package - MokoSuiteBackup
mokosuitebackup
- 02.58.35
+ 02.58.36
2026-06-02
Moko Consulting
hello@mokoconsulting.tech