Documentation · Technical Documentation

Security And Capabilities

This document describes the security model of the ADP Car Market Hub plugin: which WordPress capabilities and roles it introduces, how its admin and AJAX surfaces are guarded, and the principles it follows for input handling and external requests.

When to use this document

Read this document if you need to:

  • Decide which WordPress role to assign to a dealer or content editor.
  • Audit who can view, edit, import or change settings.
  • Add a custom role that should be able to manage vehicle listings without being a full administrator.
  • Verify the security posture of the plugin's HTTP and AJAX surfaces.

For per-endpoint capability and nonce details, see REST API Endpoints and AJAX Actions.

Overview

The plugin layers two independent capability systems:

  1. Custom CPT capabilities for as24ci_car posts (granular read/edit/publish/delete capabilities).
  2. A plugin-wide management capability (manage_as24_imports) that gates the importer admin pages, the import/queue triggers, the analytics purge, the lead workflow and the AI Assistant administration.

A dedicated role, as24ci_editor ("AS24 Editor"), is created on activation. It receives all CPT capabilities but not manage_as24_imports, allowing it to maintain vehicles without touching importer settings.

Capabilities reference

Plugin management capability

CapabilityPurpose
manage_as24_importsRequired for importer admin tabs, import/queue triggers, batch wizard, lead workflow updates, analytics purge, AI Assistant admin and support tab. Granted to the administrator role on activation.

Custom post type capabilities (as24ci_car)

The plugin maps the following meta and primitive capabilities:

  • Singular meta caps: read_as24ci_car, edit_as24ci_car, delete_as24ci_car.
  • Plural primitive caps: read_private_as24ci_cars, edit_as24ci_cars, edit_others_as24ci_cars, edit_published_as24ci_cars, publish_as24ci_cars, delete_as24ci_cars, delete_others_as24ci_cars, delete_published_as24ci_cars.

Both the administrator role and the as24ci_editor role are granted all of the above on activation. The standard WordPress editor role does not receive these capabilities by design.

Roles created by the plugin

  • as24ci_editor — created on activation with the label AS24 Editor. Starts with the read capability and then receives all as24ci_car CPT capabilities. Does not receive manage_as24_imports.
  • administrator — receives all as24ci_car CPT capabilities and manage_as24_imports. The role itself is not created by the plugin (it is part of WordPress).

The as24ci_caps_version option records the capability schema version, allowing future plugin upgrades to add new caps to existing roles without manual reactivation.

Admin and AJAX security pattern

Every admin AJAX handler in the plugin follows the same shape:

  1. Verify capability via current_user_can( CAP_MANAGE ). On failure, respond with HTTP 403 and exit.
  2. Verify the nonce via check_ajax_referer( <action>, 'nonce' ).
  3. Sanitise inputs (absint, sanitize_key, sanitize_text_field, etc.).
  4. Perform the work.
  5. Return wp_send_json_success() or wp_send_json_error().

For per-action nonces and capability requirements, see AJAX Actions.

REST and webhook security

  • The optional public vehicle endpoints (GET /as24ci/v1/vehicles[*]) are only registered when the as24ci_rest_api_enabled option equals '1'.
  • The cron-import endpoint (GET /as24ci/v1/cron-import) requires a token stored in as24ci_cron_token. The token comparison uses hash_equals() to mitigate timing attacks. Prefer the Authorization: Bearer <token> header over the query-string fallback so the token is not written to access logs.
  • The favorites and analytics endpoints are public by design so anonymous visitors can use them. Both apply input validation and rate-limit-style constraints (favorites are capped at 50 IDs per call; analytics events must use the allowed event names).
  • Outbound webhooks sign payloads with HMAC-SHA256 in the X-AS24CI-Signature header when a shared secret is configured. See Webhooks.

Input handling and escaping

  • Form inputs are sanitised via dedicated helpers (sanitize_email, sanitize_text_field, sanitize_url, wp_kses_post for message bodies, absint for IDs).
  • Output in admin templates uses esc_html(), esc_attr(), esc_url() and wp_kses_post() as appropriate.
  • Database access uses $wpdb->prepare() for parameterised queries; raw SQL is restricted to schema operations and documented phpcs ignores in the source.

Step by step instructions

Grant a non-admin user the importer admin

  1. In WordPress, edit the user profile.
  2. Add a custom role (or extend the user) with the manage_as24_imports capability.
  3. Save. The user can now access the importer admin pages, trigger imports and manage leads.

Allow vehicle authoring without importer access

  1. Assign the user to the as24ci_editor role created by the plugin.
  2. The user can read, edit, publish and delete as24ci_car posts but cannot access the importer admin or change plugin settings.

Operational notes

  • manage_as24_imports is a primitive capability on the administrator role. Removing it from administrators (for example with a custom user-management plugin) will lock all admins out of the importer and lead admin screens.
  • Capability assignments are written on activation. If a user removes a capability after activation it is not restored automatically. Plugin upgrades that introduce a new capability re-run the assignment based on the as24ci_caps_version option.
  • The plugin does not block the standard WordPress login or password flows. Use a strong password policy and consider two-factor authentication for accounts that hold manage_as24_imports.
  • Sensitive configuration (API client credentials, webhook secrets, the cron token) is stored in wp_options. On installs migrated to data version 5, reversible secrets (as24ci_client_secret, as24ci_hub_api_key, as24ci_webhook_secret) are stored AES-256-GCM-encrypted via AS24CI\Secrets, and the cron token is stored as a keyed HMAC hash. Database backups should still be treated as containing secrets. The managed Gemini API key used by the AI assistant is delivered server-to-server by the API Platform and held encrypted by AS24CI\Ai_Credential_Manager; it is not stored as a plaintext WordPress option or exposed in the admin UI.
  • The contact form sanitises inputs and uses a honeypot in some flows, but the plugin does not bundle a CAPTCHA. Pair it with a security or anti-spam plugin if your site is targeted.

Troubleshooting

  • Permission denied. when triggering an import — the user lacks manage_as24_imports. Add the capability to the user's role.
  • as24ci_editor users cannot edit vehicle posts — verify the role retained its CPT capabilities (some user-role managers strip caps when changing labels). Re-activate the plugin to re-apply the capability map, or run the relevant WP-CLI commands.
  • Cron import endpoint always returns 403 — no token is configured or the supplied value differs. Generate a new token from the Import & Limits admin tab.
  • REST /vehicles returns 404 — the public REST API is disabled. Set as24ci_rest_api_enabled to '1'.
  • Webhook signatures do not match on the receiver — recompute on the receiver using the raw, untouched request body and the same shared secret. See Webhooks.