ISSUE-116 Fix the vulnerability in pluginsChange.php
This commit is contained in:
@@ -9,9 +9,31 @@
|
||||
|
||||
use ProcessMaker\Plugins\PluginRegistry;
|
||||
|
||||
/**
|
||||
* Main execution block - handles plugin change requests and returns JSON response
|
||||
*/
|
||||
try {
|
||||
$result = handlePluginChange();
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($result);
|
||||
} catch (Exception $e) {
|
||||
// Handle any unexpected errors with proper HTTP status
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles plugin enable/disable operations with security validation
|
||||
*
|
||||
* @return array Response array with success status and details
|
||||
* @throws InvalidArgumentException When input parameters are invalid
|
||||
* @throws SecurityException When security validation fails
|
||||
* @throws FileNotFoundException When plugin files are not found
|
||||
*/
|
||||
function handlePluginChange() {
|
||||
try {
|
||||
// Validar parámetros de entrada
|
||||
// Validate required input parameters
|
||||
if (!isset($_GET['id']) || !isset($_GET['status'])) {
|
||||
throw new InvalidArgumentException('Missing required parameters');
|
||||
}
|
||||
@@ -19,40 +41,44 @@ function handlePluginChange() {
|
||||
$pluginFile = $_GET['id'];
|
||||
$pluginStatus = $_GET['status'];
|
||||
|
||||
// Validar formato del archivo de plugin
|
||||
// Validate plugin file format (alphanumeric, underscore, hyphen + .php extension)
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+\.php$/', $pluginFile)) {
|
||||
throw new InvalidArgumentException('Invalid plugin file format');
|
||||
}
|
||||
|
||||
// Validar status
|
||||
// Validate status parameter (only '0' or '1' allowed)
|
||||
if (!in_array($pluginStatus, ['0', '1'], true)) {
|
||||
throw new InvalidArgumentException('Invalid plugin status');
|
||||
}
|
||||
|
||||
// Sanitizar nombre del plugin
|
||||
// Sanitize plugin name by removing directory components and extension
|
||||
$pluginName = basename(str_replace(".php", "", $pluginFile));
|
||||
|
||||
// Additional validation for plugin name format
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $pluginName)) {
|
||||
throw new InvalidArgumentException('Invalid plugin name format');
|
||||
}
|
||||
|
||||
// Validar rutas de forma segura
|
||||
// Secure path validation to prevent directory traversal attacks
|
||||
$pluginFilePath = realpath(PATH_PLUGINS . $pluginFile);
|
||||
$pluginDirPath = realpath(PATH_PLUGINS . $pluginName);
|
||||
$pluginsDir = realpath(PATH_PLUGINS);
|
||||
|
||||
// Ensure plugin file is within the allowed plugins directory
|
||||
if (!$pluginFilePath || strpos($pluginFilePath, $pluginsDir) !== 0) {
|
||||
throw new SecurityException('Plugin file outside allowed directory');
|
||||
}
|
||||
|
||||
// Verify plugin file exists
|
||||
if (!is_file($pluginFilePath)) {
|
||||
throw new FileNotFoundException('Plugin file not found');
|
||||
}
|
||||
|
||||
// Get plugin registry singleton instance
|
||||
$oPluginRegistry = PluginRegistry::loadSingleton();
|
||||
|
||||
if ($pluginStatus === '1') {
|
||||
// Deshabilitar plugin
|
||||
// Disable plugin operation
|
||||
$details = $oPluginRegistry->getPluginDetails($pluginFile);
|
||||
if ($details) {
|
||||
$oPluginRegistry->disablePlugin($details->getNamespace());
|
||||
@@ -61,13 +87,14 @@ function handlePluginChange() {
|
||||
return ['success' => true, 'action' => 'disabled', 'plugin' => $details->getNamespace()];
|
||||
}
|
||||
} else {
|
||||
// Habilitar plugin
|
||||
// Enable plugin operation
|
||||
if ($pluginDirPath && is_dir($pluginDirPath)) {
|
||||
// Safely include the validated plugin file
|
||||
require_once($pluginFilePath);
|
||||
$details = $oPluginRegistry->getPluginDetails($pluginFile);
|
||||
if ($details) {
|
||||
$oPluginRegistry->enablePlugin($details->getNamespace());
|
||||
$oPluginRegistry->setupPlugins();
|
||||
$oPluginRegistry->setupPlugins(); // Initialize all enabled plugins
|
||||
$oPluginRegistry->savePlugin($details->getNamespace());
|
||||
G::auditLog("EnablePlugin", "Plugin Name: " . $details->getNamespace());
|
||||
return ['success' => true, 'action' => 'enabled', 'plugin' => $details->getNamespace()];
|
||||
@@ -77,21 +104,12 @@ function handlePluginChange() {
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback response if no operation was performed
|
||||
return ['success' => false, 'error' => 'Plugin operation failed'];
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Log error and return failure response
|
||||
G::auditLog('PluginChange', 'Error: ' . $e->getMessage());
|
||||
return ['success' => false, 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
// Ejecutar y devolver respuesta JSON
|
||||
try {
|
||||
$result = handlePluginChange();
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($result);
|
||||
} catch (Exception $e) {
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
Reference in New Issue
Block a user