Security Model
Security Model
Input Validation
All external input is validated before use:
| Source | Sanitizer | Example |
|---|---|---|
$_SERVER headers |
sanitize_text_field(wp_unslash(...)) |
$_SERVER['HTTP_IF_NONE_MATCH'] |
$_POST AJAX data |
sanitize_key(), absint(), sanitize_text_field() |
Tab export, import, purge |
REST API ?q= |
sanitize_callback in route schema |
/cybermaps/v1/search |
| Settings form input | Type-specific sanitizers in sanitize_callback |
All settings fields |
Output Escaping
| Context | Escaper |
|---|---|
| HTML attributes | esc_attr() |
| HTML text content | esc_html(), esc_html__() |
| URLs | esc_url() |
| JSON | wp_json_encode() with flags |
| Discovery endpoint content | Targeted phpcs:ignore after integrity checks |
CSRF Protection
- All destructive admin actions:
check_admin_referer()/check_ajax_referer() - REST
/purgeendpoint:X-WP-Nonceheader verified viawp_verify_nonce($nonce, 'wp_rest') - Tab export/import:
cybermaps_exchange_actionnonce
API Authentication
Protected REST endpoints (/urls, /status) require an API secret passed via X-Cybermaps-Secret header:
public function check_secret_permission(\WP_REST_Request $request): bool {
$secret = (string) ($settings['api_secret'] ?? '');
if ('' === $secret) return false;
$header = $request->get_header('X-Cybermaps-Secret');
return $header && hash_equals($secret, $header);
}
hash_equals() is used for timing-safe string comparison.
Capability Granularity
| Capability | Default Role | Controls Access To |
|---|---|---|
manage_options |
Administrator | All plugin settings (default WordPress cap) |
cybermaps_manage_settings |
Administrator | Plugin settings pages |
cybermaps_view_logs |
Administrator | Logs dashboard and CSV export |
cybermaps_manage_reports |
Administrator | Report generation and scheduling |
Capabilities are registered on init and assigned to the Administrator role. Agencies can create custom roles with granular access, e.g., a “Client” role with only cybermaps_view_logs.
Fatal Error Recovery
A register_shutdown_function() handler catches fatal errors and prevents site white-screens:
register_shutdown_function(static function(): void {
$error = error_get_last();
if (!$error || !in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) return;
$msg = gmdate('c') . ' ' . $error['message'] . ' in ' . $error['file'] . ':' . $error['line'];
$existing = get_option('cybermaps_fatal_errors', []);
$existing[] = $msg;
if (count($existing) > 20) $existing = array_slice($existing, -20);
update_option('cybermaps_fatal_errors', $existing);
});
The last 20 errors are stored in the cybermaps_fatal_errors option. Admin can review them without the site going down.
Direct File Access
All PHP files include:
if (!defined('ABSPATH')) {
exit;
}