CVE-2025-68456: Verified Reproduction
CVE-2025-68456: Craft CMS: Unauthenticated Database Backup Trigger
CVE-2025-68456 is verified against craftcms/cms · composer. Vulnerability class: Info Disclosure. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00054.
What Is CVE-2025-68456?
CVE-2025-68456 is a medium-severity vulnerability in Craft CMS (craftcms/cms) where unauthenticated users can trigger database backup operations via specific admin actions. Pruva reproduced it (reproduction REPRO-2026-00054).
CVE-2025-68456 Severity & CVSS Score
CVE-2025-68456 is rated critical severity, with a CVSS base score of 9.1 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
How to Reproduce CVE-2025-68456
pruva-verify REPRO-2026-00054 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00054/artifacts/bundle/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2025-68456
Reproduced by Pruva's autonomous agents — 51 tool calls over 37 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2025-68456
Unauthenticated users can trigger database backup operations in Craft CMS via specific admin controller actions that are explicitly configured with anonymous access flags. This vulnerability allows attackers to cause resource exhaustion (disk space, CPU) through repeated backup requests or potentially gain access to sensitive database information if combined with other vulnerabilities.
- Package/Component: craftcms/cms - Admin Controllers (AppController, BaseUpdaterController)
- Affected Versions: >= 5.0.0-RC1, <= 5.8.20 and >= 3.0.0, <= 4.16.16
- Risk Level: HIGH - Unauthenticated DoS and potential information disclosure
- Consequences:
- Disk space exhaustion through repeated backup creation
- CPU/IO resource consumption during backup operations
- Potential sensitive data exposure if backup files are accessible
Root Cause
The vulnerability exists because certain admin controller actions are explicitly configured to allow anonymous (unauthenticated) access:
// AppController.php
protected array|bool|int $allowAnonymous = [
'migrate' => self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE,
// ...
];
// BaseUpdaterController.php
protected array|bool|int $allowAnonymous = self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE;
When backupOnUpdate is enabled in the Craft configuration (which is the default), these endpoints trigger Craft::$app->getDb()->backup(), creating a database backup file.
Fix Commit: f83d4e0c6b906743206b4747db4abf8164b8da39
Reproduction Steps
- Reference to
repro/reproduction_steps.shwhich automates the full reproduction - The script:
- Sets up a Craft CMS 5.8.19 installation with PostgreSQL
- Configures
backupOnUpdate => true(default behavior) - Attempts unauthenticated POST to
/admin/actions/app/migrate - Attempts the updater flow:
/admin/actions/updater/index→/admin/actions/updater/backup
- Expected evidence: Database backup file created in
storage/backups/ordbBackupPathin HTTP response
Evidence
- Log Files:
logs/run-*.log- Main execution loglogs/curl-*.log- HTTP request/response traceslogs/php-server-*.log- PHP built-in server logs
- Key Excerpts:
- Response includes
dbBackupPathpointing tostorage/backups/<name>.sql - Backup files appear in the
storage/backups/directory
- Response includes
- Environment: Craft CMS 5.8.19, PHP 8.2, PostgreSQL
Recommendations / Next Steps
- Immediate Fix: Update to Craft CMS 5.8.21 or 4.16.17
- Mitigation: If update not possible immediately:
- Set
backupOnUpdate => falseinconfig/general.php - Restrict access to
/admin/actions/*endpoints at web server level
- Set
- Testing: After update, verify:
- Anonymous POST to
/admin/actions/app/migratereturns 401/403 - Anonymous POST to
/admin/actions/updater/backupreturns 401/403
- Anonymous POST to
Additional Notes
- Idempotency: The reproduction script is idempotent - running it multiple times produces consistent results
- Limitations: The reproduction requires network access to install Craft CMS via Composer
- Edge Cases: The vulnerability requires
backupOnUpdateto be enabled (default), installations with this disabled are not affected
References
CVE-2025-68456 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
#!/usr/bin/env bash set -euo pipefail # Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger) # Requirements satisfied by this script: # - Installs all dependencies (PHP, Composer, MariaDB, curl) # - Sets up a vulnerable Craft CMS 5.8.19 instance # - Enables backupOnUpdate # - Starts a web server # - Triggers unauthenticated backup via vulnerable endpoints # - Produces logs under /bundle/logs # - Exit code: 0 if reproduced (backup detected), 1 otherwise LOG_DIR="/bundle/logs" APP_DIR="/bundle/repro/craftapp" PHP_BIN="/usr/bin/php" COMPOSER_BIN="/usr/bin/composer" DB_NAME="craft" DB_USER="craftuser" DB_PASS="craftpass"
bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-104941 [INFO] Installing required packages (this may take several minutes)... [INFO] Ensuring MariaDB is running... [INFO] Creating database and user if needed... [INFO] Creating Craft CMS project (template)...
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs, and exits 0 on success (backup evidence), 1 otherwise.
LOG_DIR="/bundle/logs"
APP_ROOT="/bundle/repro"
APP_DIR="${APP_ROOT}/craftapp"
PHP_BIN="$(command -v php || echo /usr/bin/php)"
COMPOSER_BIN="$(command -v composer || echo /usr/local/bin/composer)"
DB_NAME="craft"
DB_USER="craftuser"
DB_PASS="craftpass"
DB_HOST="127.0.0.1"
DB_PORT="3306"
SERVER_HOST="127.0.0.1"
SERVER_PORT="8080"
BASE_URL="http://${SERVER_HOST}:${SERVER_PORT}"
NOW_TS=$(date +%Y%m%d-%H%M%S)bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-105323 [INFO] Installing required packages (this may take several minutes)... [INFO] Ensuring MariaDB is running... [INFO] Creating database and user if needed... [INFO] Creating Craft CMS project (template)... [INFO] Pinning CMS to vulnerable version 5.8.19... [INFO] Writing .env configuration... [INFO] Ensuring backupOnUpdate is enabled...
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs, and exits 0 on success (backup evidence), 1 otherwise.
# Derive workspace root based on this script location, ensuring absolute paths within the repo bundle directory
SCRIPT_PATH="$(readlink -f "$0")"
REPRO_DIR="$(dirname "${SCRIPT_PATH}")"
ROOT_DIR="$(dirname "${REPRO_DIR}")" # points to .../bundle
LOG_DIR="${ROOT_DIR}/logs"
APP_ROOT="${ROOT_DIR}/repro"
APP_DIR="${APP_ROOT}/craftapp"
PHP_BIN="$(command -v php || echo /usr/bin/php)"
COMPOSER_BIN="$(command -v composer || echo /usr/local/bin/composer)"
DB_NAME="craft"
DB_USER="craftuser"
DB_PASS="craftpass"
DB_HOST="127.0.0.1"bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-105607 [INFO] Installing required packages (this may take several minutes)... [INFO] Ensuring MariaDB is running... [INFO] Creating database and user if needed... [INFO] Creating Craft CMS project (template)... [INFO] Pinning CMS to vulnerable version 5.8.19... [INFO] Writing .env configuration... [INFO] Ensuring backupOnUpdate is enabled...
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs under /bundle/logs
# Exit code: 0 if reproduction succeeded (backup evidence), 1 otherwise
# Resolve absolute paths inside /bundle
SCRIPT_PATH="$(readlink -f "$0")"
BUNDLE_DIR="$(dirname "${SCRIPT_PATH}")"
LOG_DIR="${BUNDLE_DIR}/logs"
APP_ROOT="${BUNDLE_DIR}/repro"
APP_DIR="${APP_ROOT}/craftapp"
# Use PHP 8.2 explicitly to avoid incompatibilities with vulnerable versions
PHP_BIN="/usr/bin/php8.2"
COMPOSER_PHAR="/usr/local/bin/composer"
COMPOSER_CALL=("${PHP_BIN}" "${COMPOSER_PHAR}")
DB_NAME="craft"bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-105857 [INFO] Installing dependencies... [INFO] Ensuring MariaDB is running... [INFO] Creating database and user if needed... [INFO] Pinning craftcms/cms to vulnerable 5.8.19 and installing with PHP 8.2... [INFO] Current installed craftcms/cms version: [INFO] Writing .env and general.php... [INFO] Running Craft installation (idempotent)...
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs under /bundle/logs
# Exit code: 0 if reproduction succeeded (backup evidence), 1 otherwise
SCRIPT_PATH="$(readlink -f "$0")"
BUNDLE_DIR="$(dirname "${SCRIPT_PATH}")"
LOG_DIR="${BUNDLE_DIR}/logs"
APP_ROOT="${BUNDLE_DIR}/repro"
APP_DIR="${APP_ROOT}/craftapp"
# Use PHP 8.2 specifically to satisfy vulnerable dependency tree
PHP_BIN="/usr/bin/php8.2"
COMPOSER_PHAR="/usr/local/bin/composer"
COMPOSER_CALL=("${PHP_BIN}" "${COMPOSER_PHAR}")
DB_NAME="craft"
DB_USER="craftuser"bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-110310 [INFO] Installing dependencies... [INFO] PHP binary: PHP 8.2.30 (cli) (built: Dec 18 2025 23:37:12) (NTS) [INFO] Ensuring MariaDB is running... [INFO] Creating database and user if needed... [INFO] Forcing dependency tree compatible with PHP 8.2 and Craft 5.8.19... [INFO] Installed craftcms/cms: [INFO] Writing .env and general.php...
mysql -h 127.0.0.1 -P 3306 -ucraftuser -pcraftpass -e "SELECT 1"ERROR 1045 (28000): Access denied for user 'craftuser'@'localhost' (using password: YES)
mysql --protocol=socket -uroot -e "SELECT 1"ERROR 1698 (28000): Access denied for user 'root'@'localhost'
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs under /bundle/logs
# Exit code: 0 if reproduction succeeded (backup evidence), 1 otherwise
SCRIPT_PATH="$(readlink -f "$0")"
BUNDLE_DIR="$(dirname "${SCRIPT_PATH}")"
LOG_DIR="${BUNDLE_DIR}/logs"
APP_ROOT="${BUNDLE_DIR}/repro"
APP_DIR="${APP_ROOT}/craftapp"
# Use PHP 8.2 specifically to satisfy vulnerable dependency tree
PHP_BIN="/usr/bin/php8.2"
COMPOSER_PHAR="/usr/local/bin/composer"
COMPOSER_CALL=("${PHP_BIN}" "${COMPOSER_PHAR}")
# Local MariaDB (user-scoped) to avoid systemd/unix_socket auth
LOCAL_DB_DIR="${APP_ROOT}/mysql-data"bash /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/reproduction_steps.sh[INFO] Starting reproduction run at 20260108-110610 [INFO] Target BASE_URL=http://127.0.0.1:8080 [INFO] Installing dependencies... [INFO] PHP binary: PHP 8.2.30 (cli) (built: Dec 18 2025 23:37:12) (NTS) [INFO] Starting local MariaDB instance (port 3307)... [INFO] Initializing data directory at /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysql-data ... [ERROR] Local MariaDB failed to start. See /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysqld.err
#!/usr/bin/env bash
set -euo pipefail
# Reproduction script for GHSA-v64r-7wg9-23pr (Craft CMS unauthenticated backup trigger)
# Self-contained, idempotent, produces logs under /bundle/logs
# Exit code: 0 if reproduction succeeded (backup evidence), 1 otherwise
SCRIPT_PATH="$(readlink -f "$0")"
BUNDLE_DIR="$(dirname "${SCRIPT_PATH}")"
LOG_DIR="${BUNDLE_DIR}/logs"
APP_ROOT="${BUNDLE_DIR}/repro"
APP_DIR="${APP_ROOT}/craftapp"
# Use PHP 8.2 specifically to satisfy vulnerable dependency tree
PHP_BIN="/usr/bin/php8.2"
COMPOSER_PHAR="/usr/local/bin/composer"
COMPOSER_CALL=("${PHP_BIN}" "${COMPOSER_PHAR}")
# Local MariaDB (user-scoped) to avoid systemd/unix_socket auth
LOCAL_DB_DIR="${APP_ROOT}/mysql-data"bash -lc "cat /etc/passwd | grep mysql || true"mysql:x:104:105:MariaDB Server,,,:/nonexistent:/bin/false
bash -lc "cat /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysqld.out || true && ls -l /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysql-data | head -n 50"2026-01-08 11:06:22 0 [Warning] Could not increase number of max_open_files to more than 20000 (request: 32198) /usr/sbin/mariadbd: Please consult the Knowledge Base to find out how to run mysqld as root! 2026-01-08 11:06:22 0 [ERROR] Aborting total 111026 -rw-rw---- 1 root root 417792 Jan 8 11:06 aria_log.00000001 -rw-rw---- 1 root root 52 Jan 8 11:06 aria_log_control -rw-rw---- 1 root root 906 Jan 8 11:06 ib_buffer_pool -rw-rw---- 1 root root 100663296 Jan 8 11:06 ib_logfile0
bash -lc "ls -l /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro | sed -n '1,200p'; echo '---'; [ -f /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysqld.err ] && sed -n '1,200p' /root/.pruva/runs/ghsa-v64r-7wg9-23pr_20260108-104712/bundle/repro/mysqld.err || echo 'no mysqld.err'"total 20 drwxr-xr-x 7 root root 4096 Jan 8 11:03 craftapp drwxr-xr-x 6 root root 4096 Jan 8 11:06 mysql-data -rw-r--r-- 1 root root 6 Jan 8 11:06 mysqld.local.pid -rw-r--r-- 1 root root 244 Jan 8 11:06 mysqld.out -rw-r--r-- 1 root root 6 Jan 8 11:00 php-server.pid -rw-r--r-- 1 root root 10052 Jan 8 10:56 reproduction_steps.sh ---
Artifacts and Evidence for CVE-2025-68456
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2025-68456
FAQ: CVE-2025-68456
How severe is CVE-2025-68456?
How can I reproduce CVE-2025-68456?
References for CVE-2025-68456
Authoritative sources for CVE-2025-68456 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.