Security Notes

Security considerations for wpzylos-core.

PluginContext Security

Prefix Isolation

Context prefixes isolate plugin resources. Always use context methods for:

// Options
$key = $context->optionKey('settings');  // myplugin_settings

// Transients
$key = $context->transientKey('cache');  // myplugin_cache

// Custom hooks
$hook = $context->hook('data_saved');    // myplugin_data_saved

// Database tables
$table = $context->tableName('orders');  // wp_myplugin_orders

Never Expose Context Internals

Don't expose prefix or internal paths to users:

// Bad: Exposes internal structure
echo "Table: " . $context->tableName('users');

// Good: Use prefixed data, hide structure
$users = $repository->all();

Service Provider Security

Validate External Input in Boot

Providers may interact with user data during boot. Validate:

public function boot(): void
{
    $hooks = $this->app->container()->get(HookManager::class);

    $hooks->wpAction('init', function () {
        // Validate before using
        $page = sanitize_text_field($_GET['page'] ?? '');
        if ($page === $this->context->slug()) {
            // Safe to proceed
        }
    });
}

Don't Trust Configuration Blindly

If config comes from database or user input:

$providers = get_option($context->optionKey('custom_providers'), []);

// Validate before instantiating
foreach ($providers as $class) {
    if (class_exists($class) && is_subclass_of($class, ServiceProvider::class)) {
        $app->register(new $class());
    }
}

Path Security

Validate Relative Paths

When accepting user-provided paths:

// Bad: Dangerous: path traversal
$file = $context->path($_GET['template']);

// Good: Safe: validate and restrict
$template = basename($_GET['template'] ?? 'default');
$allowed = ['default', 'custom', 'minimal'];
if (in_array($template, $allowed, true)) {
    $file = $context->path('templates/' . $template . '.php');
}