{"id":312252,"date":"2026-05-13T13:11:31","date_gmt":"2026-05-13T13:11:31","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/codevera-ai-access-control\/"},"modified":"2026-05-13T13:11:25","modified_gmt":"2026-05-13T13:11:25","slug":"codevera-ai-access-control","status":"publish","type":"plugin","link":"https:\/\/he.wordpress.org\/plugins\/codevera-ai-access-control\/","author":23487798,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.1.4","stable_tag":"1.1.4","tested":"7.0","requires":"7.0","requires_php":"7.4","requires_plugins":null,"header_name":"Codevera AI Access Control","header_author":"Codevera","header_description":"Control which plugins can register abilities with the WordPress AI feature. Block any plugin, or any individual ability, from being available to AI providers.","assets_banners_color":"5c59d1","last_updated":"2026-05-13 13:11:25","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/codevera.ai","rating":0,"author_block_rating":0,"active_installs":0,"downloads":23,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.4":{"tag":"1.1.4","author":"codevera","date":"2026-05-13 13:11:25"}},"upgrade_notice":{"1.1.4":"<p>Settings screen polish. Plugin cards now collapse by default with a chevron toggle, show an allowed-count badge, and display each plugin&#039;s proper display name instead of its folder slug. Safe to update.<\/p>","1.1.3":"<p>Recommended update. Adds a Block all \/ Allow all toggle and a settings legend, fixes a duplicate save notice, removes unnecessary option autoloading, warns when the tamper-detect key has fallen back to a public default, and trims source-tracker overhead. Safe to update.<\/p>","1.1.2":"<p>Submission housekeeping. Removes the duplicate Plugin URI header to satisfy WordPress.org submission rules. No functional change.<\/p>","1.1.1":"<p>Small UX update. Saved-state banners now auto-dismiss after 2 seconds. The red tamper-detect banner is unchanged. Safe to update.<\/p>","1.1.0":"<p>Recommended security and reliability update. Adds signed settings with tamper detection, filter-level enforcement against race attacks, and a self-check that re-attaches the gate if removed. Fixes a source attribution bug for core abilities. Safe to update.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-256x256.png":{"filename":"icon-256x256.png","revision":3531010,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3531010,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3531010,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.4"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3531010,"resolution":"1","location":"assets","locale":"","width":1280,"height":800}},"screenshots":{"1":"Settings screen showing every plugin that has registered AI abilities, grouped by source, with per-plugin and per-ability checkboxes"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[251511,83,2353,396,600],"plugin_category":[54],"plugin_contributors":[262333],"plugin_business_model":[],"class_list":["post-312252","plugin","type-plugin","status-publish","hentry","plugin_tags-abilities","plugin_tags-admin","plugin_tags-ai","plugin_tags-privacy","plugin_tags-security","plugin_category-security-and-spam-protection","plugin_contributors-codevera","plugin_committers-codevera"],"banners":{"banner":"https:\/\/ps.w.org\/codevera-ai-access-control\/assets\/banner-772x250.png?rev=3531010","banner_2x":"https:\/\/ps.w.org\/codevera-ai-access-control\/assets\/banner-1544x500.png?rev=3531010","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/codevera-ai-access-control\/assets\/icon-256x256.png?rev=3531010","icon_2x":"https:\/\/ps.w.org\/codevera-ai-access-control\/assets\/icon-256x256.png?rev=3531010","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/codevera-ai-access-control\/assets\/screenshot-1.png?rev=3531010","caption":"Settings screen showing every plugin that has registered AI abilities, grouped by source, with per-plugin and per-ability checkboxes"}],"raw_content":"<!--section=description-->\n<p>WordPress 7.0 introduced the Abilities API. Any active plugin can register an ability and the WordPress AI feature can then invoke it, consuming whatever credits or tokens your AI provider charges per call. By default every registered ability is exposed, and there is no built-in way to see what is exposed or to limit it.<\/p>\n\n<p>Codevera AI Access Control adds a single settings screen that lists every plugin which has registered AI abilities, grouped by source plugin, and lets you allow or block each plugin as a whole or each individual ability.<\/p>\n\n<p><strong>How it works:<\/strong><\/p>\n\n<ol>\n<li>The plugin watches every call to <code>wp_register_ability()<\/code> and records which plugin made the call.<\/li>\n<li>The Settings -&gt; Codevera AI Access screen groups those abilities by source plugin so you can see at a glance what is exposed.<\/li>\n<li>Untick a plugin or a single ability and save. From the next request onwards, the AI feature can no longer see or invoke it.<\/li>\n<\/ol>\n\n<p><strong>Free:<\/strong><\/p>\n\n<ul>\n<li>Per-plugin and per-ability granular controls<\/li>\n<li>Automatic detection of newly installed plugins that register AI abilities, with an in-admin notification so you can review them<\/li>\n<li>Tamper-detect signature on the saved settings, with a fail-closed mode that blocks every non-core ability if the settings option is modified outside the plugin<\/li>\n<li>Filter-level enforcement that neutralises a blocked ability before WordPress constructs it, plus a registry sweep that removes blocked abilities from the listings<\/li>\n<li>Self-check that re-attaches the enforcement hooks on init, admin_init and rest_api_init if another plugin removes them<\/li>\n<li>Search and filter inside each plugin card so large registries stay readable<\/li>\n<li>No external requests, no telemetry, no licence checks<\/li>\n<li>Works on multisite (per-site settings)<\/li>\n<li>Translation ready<\/li>\n<\/ul>\n\n<p><strong>Works well for:<\/strong><\/p>\n\n<ul>\n<li>Sites where editorial staff use the WordPress AI feature and you want strict control over what context the AI can pull in<\/li>\n<li>Agency sites where new plugins are installed regularly and you want to review their AI exposure before letting them in<\/li>\n<li>Privacy-sensitive sites that need an explicit allow list of which plugins may expose data to an AI provider<\/li>\n<li>Compliance-driven environments that need an auditable record of which plugins have been allowed to register AI abilities<\/li>\n<\/ul>\n\n<p><strong>Under the hood:<\/strong><\/p>\n\n<ul>\n<li>Uses only the official Abilities API surface: <code>wp_register_ability_args<\/code>, <code>wp_abilities_api_init<\/code>, <code>wp_unregister_ability<\/code><\/li>\n<li>Source attribution from <code>debug_backtrace()<\/code> of the file that called <code>wp_register_ability<\/code>, normalised to a plugin slug<\/li>\n<li>HMAC-SHA256 signature on the settings option, keyed to a <code>CVAIAC_SECRET<\/code> constant or <code>AUTH_SALT<\/code> fallback<\/li>\n<li>No frontend assets shipped, all code runs in admin and on the AI Abilities REST routes<\/li>\n<li>No database tables, just two options in <code>wp_options<\/code><\/li>\n<\/ul>\n\n<h3>External Services &amp; Privacy<\/h3>\n\n<p>This plugin does not contact any external service. It reads only local WordPress data. No telemetry, no analytics, no licence checks, no remote update checks beyond what WordPress core itself performs.<\/p>\n\n<p>The plugin stores two options in the <code>wp_options<\/code> table:<\/p>\n\n<ul>\n<li><code>cvaiac_settings<\/code> - your allow and block selections, signed with an HMAC-SHA256 signature<\/li>\n<li><code>cvaiac_ability_sources<\/code> - a map of ability name to source plugin slug, populated automatically as plugins register their abilities<\/li>\n<li><code>cvaiac_schema_version<\/code> - an integer that records the storage format version, used for migration<\/li>\n<\/ul>\n\n<p>No personal data, no visitor data, and no AJAX requests to remote services.<\/p>\n\n<p>When the plugin is uninstalled, all three options are removed.<\/p>\n\n<h3>Support<\/h3>\n\n<p>Email info@codevera.ai for support, bug reports, or feature requests. Include your WordPress version, PHP version, a list of other plugins that register AI abilities, and a description of the issue with steps to reproduce.<\/p>\n\n<h3>Technical Requirements<\/h3>\n\n<p>Minimum:<\/p>\n\n<ul>\n<li>WordPress 7.0 (required for the Abilities API)<\/li>\n<li>PHP 7.4<\/li>\n<\/ul>\n\n<p>Recommended:<\/p>\n\n<ul>\n<li>WordPress 7.0 or higher<\/li>\n<li>PHP 8.0 or higher<\/li>\n<\/ul>\n\n<h3>Privacy &amp; Security<\/h3>\n\n<p>The plugin does not collect or transmit any personal data. The settings option is stored locally and signed with an HMAC keyed to a site-specific secret. The source-tracker option contains only plugin slugs and ability names that are already public to any code running on the site.<\/p>\n\n<p>Form submissions use a nonce and require the <code>manage_options<\/code> capability. The enforcement hooks run on every request that loads the Abilities API, so blocking takes effect from the next request after a setting is saved.<\/p>\n\n<p>This plugin defends against opportunistic interference such as another plugin writing directly to the settings option, removing the enforcement hooks, or re-registering an ability that has already been blocked. It does not claim to be a security boundary against a fully hostile plugin that has code execution in the same PHP process. The safest practice is still to only install plugins you trust.<\/p>\n\n<h3>Links<\/h3>\n\n<ul>\n<li>Website: https:\/\/codevera.ai<\/li>\n<li>Support: info@codevera.ai<\/li>\n<\/ul>\n\n<!--section=installation-->\n<p><strong>From WordPress admin:<\/strong><\/p>\n\n<ol>\n<li>Go to Plugins -&gt; Add new<\/li>\n<li>Search for \"Codevera AI Access Control\"<\/li>\n<li>Click Install now and then Activate<\/li>\n<li>Go to Settings -&gt; Codevera AI Access<\/li>\n<li>Review the list of plugins that have registered AI abilities<\/li>\n<li>Untick anything you do not want the AI feature to use<\/li>\n<li>Click Save changes<\/li>\n<\/ol>\n\n<p><strong>Manual installation:<\/strong><\/p>\n\n<ol>\n<li>Download the plugin zip file<\/li>\n<li>Upload to the <code>\/wp-content\/plugins\/<\/code> directory<\/li>\n<li>Extract the files<\/li>\n<li>Activate through the Plugins menu in WordPress<\/li>\n<li>Configure as described above<\/li>\n<\/ol>\n\n<p><strong>Optional hardening:<\/strong><\/p>\n\n<p>Add the following line to your <code>wp-config.php<\/code> to use a dedicated secret for the settings signature, rather than reusing <code>AUTH_SALT<\/code>:<\/p>\n\n<pre><code>define( 'CVAIAC_SECRET', 'some-long-random-string-that-only-you-know' );\n<\/code><\/pre>\n\n<p>This makes it harder for an attacker who only has database access to forge a valid settings blob.<\/p>\n\n<p><strong>After activation:<\/strong><\/p>\n\n<ul>\n<li>Visit Settings -&gt; Codevera AI Access to see which plugins have registered abilities<\/li>\n<li>Untick any plugin or ability you do not want to expose to the AI feature<\/li>\n<li>Save changes<\/li>\n<li>When a new plugin is installed and registers an ability, you will see a Newly detected items banner the next time you open the settings screen<\/li>\n<\/ul>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20make%20any%20external%20network%20requests%3F\"><h3>Does this plugin make any external network requests?<\/h3><\/dt>\n<dd><p>No. It reads only local WordPress data and never contacts any third-party service. No telemetry, no analytics, no licence checks.<\/p><\/dd>\n<dt id=\"does%20it%20store%20any%20personal%20data%3F\"><h3>Does it store any personal data?<\/h3><\/dt>\n<dd><p>No. It stores only your allow and block selections and a short list of plugin and ability identifiers in the WordPress options table.<\/p><\/dd>\n<dt id=\"how%20does%20it%20actually%20block%20an%20ability%3F\"><h3>How does it actually block an ability?<\/h3><\/dt>\n<dd><p>Two layers. First, on the <code>wp_register_ability_args<\/code> filter at the highest priority, the plugin rewrites the <code>execute_callback<\/code> and <code>permission_callback<\/code> of any blocked ability to return a <code>cvaiac_blocked<\/code> WP_Error. This neutralises the ability before WordPress even constructs it. Second, on the <code>wp_abilities_api_init<\/code> action at the highest priority, the plugin walks the registry and calls <code>wp_unregister_ability()<\/code> on anything blocked, so it disappears from the listings entirely.<\/p><\/dd>\n<dt id=\"can%20i%20block%20wordpress%20core%20abilities%3F\"><h3>Can I block WordPress core abilities?<\/h3><\/dt>\n<dd><p>You can block individual core abilities, but the WordPress core group as a whole cannot be blocked. Blocking individual core abilities can prevent the AI feature from working correctly, so do it with care.<\/p><\/dd>\n<dt id=\"what%20is%20the%20tamper-detect%20mode%3F\"><h3>What is the tamper-detect mode?<\/h3><\/dt>\n<dd><p>The settings option is stored as a JSON payload with an HMAC-SHA256 signature, keyed to a <code>CVAIAC_SECRET<\/code> constant or <code>AUTH_SALT<\/code>. Each time the plugin reads the option, the signature is recomputed and checked. If it does not match, the plugin enters fail-closed mode and blocks every non-core ability until an administrator re-saves the settings through the UI. A red banner appears on the settings screen explaining what happened.<\/p><\/dd>\n<dt id=\"why%20is%20fail-closed%20important%3F\"><h3>Why is fail-closed important?<\/h3><\/dt>\n<dd><p>A malicious or buggy plugin running on the same site can call <code>update_option( 'cvaiac_settings', array() )<\/code> to wipe your block list. With tamper detect, that write produces an invalid signature, the plugin notices, and the AI feature loses access to every plugin's abilities until you investigate and re-save.<\/p><\/dd>\n<dt id=\"can%20a%20hostile%20plugin%20still%20bypass%20this%3F\"><h3>Can a hostile plugin still bypass this?<\/h3><\/dt>\n<dd><p>A determined plugin with code execution on the same site can in principle override the <code>pre_option_cvaiac_settings<\/code> filter, remove the enforcement hooks, or read <code>CVAIAC_SECRET<\/code> from <code>wp-config.php<\/code> to forge a valid signature. This plugin defends against opportunistic interference, not against a fully hostile plugin in the same PHP process. Treat it as a policy and tamper-detect tool, not a security boundary. The safest practice is still to only install plugins you trust.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20multisite%3F\"><h3>Does it work on multisite?<\/h3><\/dt>\n<dd><p>Yes. Settings are stored per-site, so each sub-site can have its own allow and block list.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20the%20rest%20api%20run%20endpoint%3F\"><h3>Does it work with the REST API run endpoint?<\/h3><\/dt>\n<dd><p>Yes. Blocked abilities are unregistered from the registry, so the WordPress core REST run endpoint cannot find or execute them.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20uninstall%20the%20plugin%3F\"><h3>What happens when I uninstall the plugin?<\/h3><\/dt>\n<dd><p>All of the plugin's options are deleted by <code>uninstall.php<\/code>. No data is left behind.<\/p><\/dd>\n<dt id=\"can%20i%20translate%20this%20plugin%3F\"><h3>Can I translate this plugin?<\/h3><\/dt>\n<dd><p>Yes. The text domain is <code>codevera-ai-access-control<\/code>. PO files can be generated with WP-CLI or any standard translation tool.<\/p><\/dd>\n<dt id=\"how%20do%20i%20troubleshoot%3F\"><h3>How do I troubleshoot?<\/h3><\/dt>\n<dd><p>Enable <code>WP_DEBUG<\/code> and <code>WP_DEBUG_LOG<\/code> in <code>wp-config.php<\/code>. The plugin uses only standard WordPress APIs, so any issue will appear in the standard debug log.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Collapsed each plugin card by default and added a chevron toggle, so the settings screen stays compact when many plugins register abilities.<\/li>\n<li>Added an allowed-count badge to every plugin card that shows how many of its abilities are currently allowed for AI, with a red badge when none are allowed and a green badge when all are allowed.<\/li>\n<li>Replaced the raw plugin folder slug in each card heading with the plugin's display name, and moved the folder slug to a smaller secondary line for reference.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>Added a Block all and Allow all toggle to the settings screen so administrators can clear or tick every plugin and ability in one click.<\/li>\n<li>Added an on-screen legend that explains a ticked box means the plugin or ability is allowed for AI, and an unticked box means it is blocked.<\/li>\n<li>Stopped a duplicate Settings saved notice from appearing after save by namespacing the success flag so it no longer collides with WordPress core.<\/li>\n<li>Stopped the cvaiac_settings and cvaiac_schema_version options from autoloading on every request. Both options are now read on demand only.<\/li>\n<li>Added an admin notice that warns when neither CVAIAC_SECRET nor AUTH_SALT is defined in wp-config.php, so site owners know the tamper-detect signature is using a public fallback key.<\/li>\n<li>Reduced source-tracker overhead by skipping the debug_backtrace call when an ability's source plugin is already known from a previous request.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Removed the redundant Plugin URI header so it no longer matches the Author URI, which is a WordPress.org submission requirement.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Auto-dismiss the Settings saved and Newly detected items acknowledged banners after 2 seconds, so the screen tidies itself up after a save. The red tamper-detect banner is unaffected and stays until you re-save.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Added an HMAC-SHA256 signature on the settings option so direct database writes to <code>cvaiac_settings<\/code> are detected. A failed check puts the plugin into fail-closed mode and shows a red banner until an administrator re-saves the settings<\/li>\n<li>Added a <code>CVAIAC_SECRET<\/code> constant for sites that want a dedicated signing key in <code>wp-config.php<\/code> rather than the <code>AUTH_SALT<\/code> fallback<\/li>\n<li>Added filter-level enforcement on <code>wp_register_ability_args<\/code> so blocked abilities are neutralised before WordPress constructs them, closing a same-priority race where another plugin could re-register a blocked ability at PHP_INT_MAX<\/li>\n<li>Added a self-check on init, admin_init and rest_api_init that re-attaches the enforcement hooks if another plugin removes them<\/li>\n<li>Fixed source attribution for abilities registered by WordPress core. The source tracker now reads the immediate caller of <code>wp_register_ability<\/code> rather than the first plugin-dir frame on the stack, so core abilities are correctly attributed to \"core\" even when a plugin's code triggers the lazy registry init<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Settings screen grouping registered abilities by source plugin<\/li>\n<li>Per-plugin and per-ability allow and block controls<\/li>\n<li>Source tracking using <code>wp_register_ability_args<\/code> filter and <code>debug_backtrace()<\/code><\/li>\n<li>Registry sweep on <code>wp_abilities_api_init<\/code> to unregister blocked abilities<\/li>\n<li>Newly detected items notification with an Acknowledge action<\/li>\n<li>Uninstall script that removes all plugin options<\/li>\n<\/ul>","raw_excerpt":"Decide which plugins are allowed to expose their abilities to the WordPress AI feature. Block any plugin, or any single ability, with one click.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/312252","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=312252"}],"author":[{"embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/codevera"}],"wp:attachment":[{"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=312252"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=312252"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=312252"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=312252"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=312252"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/he.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=312252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}