How to create a restricted wrapper that allows AI to safely use WP-CLI

Illustration where the gate screens operations from the host and AI towards WordPress, allowing only safe operations to pass through. AI site management

It is important to instruct the AI ​​to “do not use the deletion command,” but that statement alone cannot protect the production site. This is because unexpected commands may be selected due to misinterpretation of the request, typos, instructions added later, etc.

There, we prevent direct execution of WP-CLI from AI and place an interface that accepts only a few operations approved by the administrator in between. This interface is a “restricted wrapper.”

This article is an explanation to help you understand the mechanism. Before implementation, please check the permissions, backup, and test environment in Preparation before passing WP-CLI to AI.Request work to change server users and privileges to your contract partner or server administrator.

What is a restricted wrapper?

Regular WP-CLI has functions such as not only checking articles, but also deleting, updating, database operations, and executing arbitrary PHP code. The official command list also includes commands that require careful handling, such as wp db, wp eval, wp search-replace, and wp user.

With the restricted wrapper, the string input by the AI ​​will not be passed to wp as is. For example, only the following three are accepted as unique operation names:

  • site-status: Check WordPress version and status
  • plugin-status: Check the list of plugins
  • post-list: Check the list of published articles or drafts

Inside the wrapper, we convert each one to an administrator-verified WP-CLI command. If the operation name does not match, it will not be executed and will result in an error.

Writing rules and technical restrictions have different roles

In AGENTS.md and CLAUDE.md, write operational rules such as “Only read at first” and “Publishing, deletion, and updating require human approval.”This helps AI and humans share decision criteria.

Restricted wrappers, on the other hand, stop unauthorized operations in their execution path.

Host request
↓
Codex・Claude Code
↓
Restricted wrapper ─ Deny unauthorized operations
↓
Fixed WP-CLI commands
↓
WordPress

The basics are to check the rules of the text, the wrapper, the OS and WordPress permissions, and repeated checks by people. A wrapper alone does not guarantee safety.

Safe Design Principles

1. Start with the permission list

Instead of “prohibiting only dangerous commands”, we will “allow only operations that can be used”.WP-CLI also has commands that come from additional packages and plugins, so the prohibited list may miss unknown operations.

At first, just check the status, then add operations one by one as needed.

2. Do not accept WP-CLI strings as is

If you can pass a free command string like wp post list ... to the wrapper, loopholes in the inspection will easily occur. Take your own operation name, like post-list, and keep the actual command and arguments fixed inside the wrapper.

eval should not re-execute the input string or pass the entire input to the shell.

3. Pin the target site

WP-CLI has global arguments that can be changed. --path, --url, --ssh, --require, --exec, etc. will not be freely handed over from outside, and the WordPress location and target URL will be fixed by the administrator.

4. Use a dedicated execution user

Do not share your regular administrator account or root with AI.Prepare a dedicated user with only the scope necessary to check WordPress, and remove unnecessary permissions such as interactive shell, file writing, and transfer functions.

When specifying users on the WordPress side, narrow it down to the permissions necessary for the work, not the administrator.

5. Record and limit the number

Record the execution date and time, operation name, success/failure, and target ID.However, the article text, setting values, and authentication information will not be saved in the log. We also set limits on the number of executions and acquisitions at one time.

Minimal example of a read-only wrapper

Below is a sample for a hypothetical environment to explain how it works. It does not include the actual WordPress location or running user. Rather than installing it in production as is, the administrator should design the owner, permissions, logs, and execution method according to the environment.

#!/usr/bin/env bash
set -euo pipefail

readonly PATH=/usr/local/bin:/usr/bin:/bin
readonly WP=/usr/local/bin/wp
readonly SITE=/srv/example/wordpress

action=${1:-}
shift || true

# 想定外の追加引数はすべて拒否する
if (( $# != 0 )); then
  echo "追加の引数は使用できません" >&2
  exit 64
fi

case "$action" in
  site-status)
    "$WP" --path="$SITE" core version
    "$WP" --path="$SITE" core is-installed
    ;;
  plugin-status)
    "$WP" --path="$SITE" plugin list \
      --fields=name,status,version --format=table
    ;;
  post-list)
    "$WP" --path="$SITE" post list \
      --post_type=post \
      --post_status=publish,draft \
      --fields=ID,post_title,post_status \
      --posts_per_page=20 \
      --format=table
    ;;
  *)
    echo "許可されていない操作です" >&2
    exit 64
    ;;
esac

The point is that the entire external input is not passed to WP-CLI like wp "$@".The executable file, WordPress location, subcommands, and options are fixed on the wrapper side.

If via SSH, also fix the entrance

When connecting to a VPS via SSH, consider a design that separates the AI-specific key from the user and prevents users from opening a free shell after connecting. OpenSSH’s ForceCommand can run fixed commands instead of client-specified commands.

However, ForceCommand alone does not stop port forwarding and agent forwarding. The official OpenSSH manual also explains that if it is not needed, it must be disabled separately using DisableForwarding.

If the SSH settings are incorrect, the administrator may be unable to connect. The production company or administrator should perform a configuration check and a connection test in a separate session, leaving the current connection intact, and configure the settings.

Additional conditions when allowing draft creation

If you allow article creation after reading, instead of giving free wp post create, create a separate entrance for “creating a new post as a draft.”

  • post_type is fixed to post
  • post_status is fixed to draft
  • Only one item at a time
  • Inspect slug character type and length
  • Limit the location where the main text file can be read to the dedicated directory
  • Select category ID from allowed candidates
  • Report post ID and preview destination after creation
  • Changes to publish are separated into separate approved processes

WP-CLI’s wp post create can specify the posting status, so it can be fixed to draft on the wrapper side. However, even drafts can store inappropriate content or personal information. After registration, a person always confirms it on the management screen.

Rappers that should not be made

An implementation like the following, even with the name “safety wrapper”, is not restrictive enough:

# 外部入力を何でもWP-CLIへ渡してしまう
wp "$@"

# 文字列を再びシェルとして解釈してしまう
eval "$SSH_ORIGINAL_COMMAND"

Also avoid checks like “Allow if it does not contain the word delete“.This is because you miss alternative update paths, shorthand expressions, and additional commands.

Checklist before installation

  • The execution user is different from the administrator.
  • Any operation name other than the one allowed will result in an error.
  • Reject extra arguments, unknown options, and multiple operations
  • The location of WP-CLI and WordPress is fixed.
  • Not using eval or free shell
  • Unable to call PHP execution, DB operation, setting display, update, delete
  • Restricts SSH shell and various transfers
  • Wrapper and configuration files cannot be rewritten from the AI side
  • Audit logs that do not contain confidential information remain
  • Confirmed both “allow” and “deny” in test environment
  • Checked not only backup but also restoration method
  • Publication, updating, and deletion stop with human approval

Example of request to AI

This site does not run WP-CLI directly, but instead uses a
Use only restricted wrappers.

First check the available operation names, this time read-only
Use only site-status, plugin-status, and post-list.

Unauthorized operations, additional arguments, configuration changes, updates, deletions,
Please do not publish. Report the operation name and result performed,
Please do not display personal or confidential information in your answers.

This request text is a rule that helps you make decisions. Used in combination with execution path restrictions.

Summary

When letting AI help with WP-CLI, we not only prohibit dangerous operations in writing, but also provide a physical entrance that only allowed operations can pass through.

Start with about three read-only options and test what you can deny. After that, add special operations one by one as needed, such as “Create a draft” and “Check the HTTP response of a published page.”The actual process is explained in Procedures from backup to article publication, HTTP, and display confirmation.

If you are new to WP-CLI, please read What is WP-CLI?Check out the basics and safe way to get started before letting AI help you with WordPress.The overall rules for AI operation are summarized in Safety rules for managing WordPress with AI, and the list of articles is summarized in Web operation guide for the host.

How these are combined in actual operation and how failures are reflected in the rules is introduced in Neko Yado Research’s AI/WP-CLI operation example.

Reference materials

Note: Server, SSH, and WordPress configurations vary depending on the contract. Before changing settings, check the official manual and maintenance contract, and prepare a recovery method in case of connection loss.

Title and URL copied