uiXpress
Role Editor

Security Documentation

Comprehensive security implementation details for the Role Editor feature.

Security Overview

The Role Editor implements multiple layers of security to protect WordPress installations from unauthorized access, injection attacks, and data manipulation. All security measures follow WordPress coding standards and best practices.

Authentication & Authorization

Page-Level Security

Capability Check:

  • Requires manage_options capability
  • Checked in setup_admin_page() method
  • Checked in render_page() method
  • Prevents unauthorized access

Implementation:

if (!current_user_can("manage_options")) {
    return; // or wp_die()
}

Access Control:

  • Only administrators can access
  • Menu item hidden for non-admins
  • Page content protected
  • Scripts only loaded for authorized users

REST API Security

Permission Callback:

  • All endpoints use permissions_check() method
  • Verifies manage_options capability
  • Returns 401 error if unauthorized
  • Consistent across all endpoints

Nonce Verification:

  • CSRF protection via nonce
  • Checks X-WP-Nonce header
  • Falls back to _wpnonce parameter
  • Verifies against wp_rest action
  • Returns 403 error if invalid

Implementation:

public function permissions_check($request)
{
    if (!current_user_can("manage_options")) {
        return new \WP_Error("rest_forbidden", ...);
    }
    
    $nonce = $request->get_header('X-WP-Nonce') ?: $request->get_param('_wpnonce');
    if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
        return new \WP_Error('rest_forbidden', ...);
    }
    
    return true;
}

Input Validation

Role Slug Validation

Format Validation:

  • Regex pattern: /^[a-zA-Z0-9_-]+$/
  • Only allows alphanumeric, hyphens, underscores
  • Prevents injection attacks
  • Validated on all endpoints

Length Validation:

  • Maximum 60 characters
  • Prevents buffer overflow
  • WordPress standard limit
  • Error message on violation

Implementation:

if (!preg_match('/^[a-zA-Z0-9_-]+$/', $role_slug)) {
    return new \WP_Error('rest_invalid_role', ...);
}

Capability Validation

Format Validation:

  • Regex pattern: /^[a-z0-9_]+$/
  • Only lowercase letters, numbers, underscores
  • Prevents malicious capabilities
  • Validated before assignment

Existence Validation:

  • Checks against available capabilities
  • Only allows existing capabilities
  • Prevents custom capability injection
  • Whitelist approach

Type Validation:

  • Ensures string type
  • Array validation
  • Prevents type confusion
  • Type checking before processing

Implementation:

foreach ($capabilities as $cap) {
    if (!is_string($cap)) {
        continue;
    }
    $cap = sanitize_text_field($cap);
    if (preg_match('/^[a-z0-9_]+$/', $cap) && in_array($cap, $all_capabilities)) {
        $validated_capabilities[] = $cap;
    }
}

Role Name Validation

Sanitization:

  • wp_strip_all_tags() removes HTML
  • trim() removes whitespace
  • sanitize_text_field() sanitizes
  • Prevents XSS attacks

Length Validation:

  • Maximum 100 characters
  • Minimum 1 character
  • Prevents buffer issues
  • User-friendly limits

Implementation:

$new_name = isset($body['name']) ? sanitize_text_field($body['name']) : '';
$new_name = wp_strip_all_tags($new_name);
$new_name = trim($new_name);

if (empty($new_name) || strlen($new_name) > 100) {
    return new \WP_Error('rest_invalid_name', ...);
}

Output Escaping

User Data Escaping

Script Tag Attributes:

  • esc_url() for URLs
  • esc_attr() for attributes
  • absint() for integers
  • Prevents XSS in attributes

Implementation:

wp_print_script_tag([
    "plugin-base" => esc_url($url),
    "rest-base" => esc_url(rest_url()),
    "user-id" => absint($current_user->ID),
    "user-name" => esc_attr($current_user->display_name),
    "user-email" => esc_attr($current_user->user_email),
]);

Response Data Escaping

REST API Responses:

  • All strings sanitized
  • Role slugs sanitized
  • Capability names sanitized
  • User counts cast to integers

Implementation:

return new \WP_REST_Response([
    'slug' => sanitize_text_field($role_slug),
    'capabilities' => array_map('sanitize_text_field', $capabilities),
    'userCount' => absint($users_with_role),
], 200);

Protection Mechanisms

Default Role Protection

Protected Roles:

  • Administrator
  • Editor
  • Author
  • Contributor
  • Subscriber

Deletion Prevention:

  • Hardcoded list check
  • Returns 403 error
  • Clear error message
  • Prevents system breakage

Implementation:

$default_roles = ['administrator', 'editor', 'author', 'contributor', 'subscriber'];
if (in_array($role_slug, $default_roles)) {
    return new \WP_Error('rest_cannot_delete_default', ...);
}

User Count Protection

Deletion Check:

  • Counts users with role
  • Prevents orphaned users
  • Returns 409 error
  • Suggests reassignment

Implementation:

$user_count = count_users();
$users_with_role = isset($user_count['avail_roles'][$role_slug]) 
    ? absint($user_count['avail_roles'][$role_slug]) 
    : 0;

if ($users_with_role > 0) {
    return new \WP_Error('rest_role_has_users', ...);
}

Role Existence Validation

Existence Checks:

  • Validates role exists before operations
  • Prevents errors on invalid roles
  • Returns 404 for missing roles
  • Consistent error handling

Implementation:

if (!isset($wp_roles->roles[$role_slug])) {
    return new \WP_Error('rest_invalid_role', ...);
}

Frontend Security

Client-Side Validation

Route Parameter Validation:

  • Validates role slug format
  • Prevents invalid API calls
  • User-friendly error messages
  • Prevents unnecessary requests

Input Validation:

  • Role name format
  • Role slug format
  • Capability array format
  • Length validation

Implementation:

const isValidRoleSlug = (slug) => {
    if (!slug || typeof slug !== 'string') return false;
    return /^[a-z0-9_-]+$/.test(slug);
};

Nonce Handling

Nonce Transmission:

  • Sent in X-WP-Nonce header
  • Included in all requests
  • Retrieved from script tag
  • Stored in app store

Implementation:

payload.headers = {
    'Content-Type': 'application/json',
    'X-WP-Nonce': restNonce,
};

Security Best Practices

Defense in Depth

Multiple Layers:

  • Frontend validation
  • Backend validation
  • Capability checks
  • Nonce verification
  • Input sanitization
  • Output escaping

Principle of Least Privilege

Capability Requirements:

  • Only manage_options required
  • No additional capabilities
  • Minimal permissions
  • Role-specific access

Fail Secure

Error Handling:

  • Fail closed on errors
  • Clear error messages
  • No information leakage
  • Graceful degradation

Input Validation

Whitelist Approach:

  • Only allow valid formats
  • Reject invalid input
  • Validate before processing
  • Sanitize all inputs

Output Escaping

Context-Aware Escaping:

  • HTML attributes: esc_attr()
  • URLs: esc_url()
  • Integers: absint()
  • Text fields: sanitize_text_field()

Security Audit Checklist

Authentication

  • ✅ Page access requires manage_options
  • ✅ REST API requires manage_options
  • ✅ User existence verified
  • ✅ Session validation

Authorization

  • ✅ Capability checks on all endpoints
  • ✅ Role existence validation
  • ✅ Default role protection
  • ✅ User count checks

Input Validation

  • ✅ Role slug format validation
  • ✅ Capability format validation
  • ✅ Role name sanitization
  • ✅ Length validation
  • ✅ Type validation

Output Escaping

  • ✅ User data escaped
  • ✅ URLs escaped
  • ✅ Attributes escaped
  • ✅ Response data sanitized

CSRF Protection

  • ✅ Nonce verification
  • ✅ Header-based nonce
  • ✅ Parameter fallback
  • ✅ Action verification

Error Handling

  • ✅ Secure error messages
  • ✅ No information leakage
  • ✅ User-friendly messages
  • ✅ Proper HTTP status codes

Security Recommendations

For Administrators

  1. Regular Audits: Review roles and capabilities regularly
  2. Minimal Permissions: Assign only necessary capabilities
  3. Test Changes: Test role changes on staging first
  4. Backup Before Changes: Always backup before major changes
  5. Monitor User Counts: Check user counts before deleting roles

For Developers

  1. Follow WordPress Standards: Use WordPress security functions
  2. Validate Everything: Never trust user input
  3. Escape Output: Always escape before output
  4. Use Nonces: Always verify nonces
  5. Check Capabilities: Always verify permissions

Security Testing

Test Cases

Authentication Tests:

  • Non-admin cannot access page
  • Non-admin cannot access API
  • Invalid nonce rejected
  • Missing nonce rejected

Validation Tests:

  • Invalid role slug rejected
  • Invalid capability rejected
  • Long inputs rejected
  • Special characters rejected

Protection Tests:

  • Default roles cannot be deleted
  • Roles with users cannot be deleted
  • Invalid roles return 404
  • Malformed requests rejected

Security Updates

Version History

1.2.12:

  • Initial security implementation
  • Full authentication checks
  • Input validation
  • Output escaping
  • CSRF protection

Future Enhancements

  • Rate limiting for API endpoints
  • Audit logging for role changes
  • Two-factor authentication support
  • Role change notifications
  • Security event tracking