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:
- Custom CPT capabilities for
as24ci_carposts (granular read/edit/publish/delete capabilities). - 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
| Capability | Purpose |
|---|---|
manage_as24_imports | Required 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 thereadcapability and then receives allas24ci_carCPT capabilities. Does not receivemanage_as24_imports.administrator— receives allas24ci_carCPT capabilities andmanage_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:
- Verify capability via
current_user_can( CAP_MANAGE ). On failure, respond with HTTP403and exit. - Verify the nonce via
check_ajax_referer( <action>, 'nonce' ). - Sanitise inputs (
absint,sanitize_key,sanitize_text_field, etc.). - Perform the work.
- Return
wp_send_json_success()orwp_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 theas24ci_rest_api_enabledoption equals'1'. - The cron-import endpoint (
GET /as24ci/v1/cron-import) requires a token stored inas24ci_cron_token. The token comparison useshash_equals()to mitigate timing attacks. Prefer theAuthorization: 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-Signatureheader 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_postfor message bodies,absintfor IDs). - Output in admin templates uses
esc_html(),esc_attr(),esc_url()andwp_kses_post()as appropriate. - Database access uses
$wpdb->prepare()for parameterised queries; raw SQL is restricted to schema operations and documentedphpcsignores in the source.
Step by step instructions
Grant a non-admin user the importer admin
- In WordPress, edit the user profile.
- Add a custom role (or extend the user) with the
manage_as24_importscapability. - Save. The user can now access the importer admin pages, trigger imports and manage leads.
Allow vehicle authoring without importer access
- Assign the user to the
as24ci_editorrole created by the plugin. - The user can read, edit, publish and delete
as24ci_carposts but cannot access the importer admin or change plugin settings.
Operational notes
manage_as24_importsis a primitive capability on theadministratorrole. 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_versionoption. - 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 viaAS24CI\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 byAS24CI\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 lacksmanage_as24_imports. Add the capability to the user's role.as24ci_editorusers 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
/vehiclesreturns404— the public REST API is disabled. Setas24ci_rest_api_enabledto'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.