AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Wp Cli Security

skill-wpultimatesecurity-wordpress-security-skills-wp-cli-security · by wpultimatesecurity

>

— No reviews yet
0 installs
32 views
0.0% view→install

Install

$ agentstack add skill-wpultimatesecurity-wordpress-security-skills-wp-cli-security

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-wpultimatesecurity-wordpress-security-skills-wp-cli-security)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 17d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Wp Cli Security? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

WP-CLI security

When to use this skill

Use this skill whenever code registers or implements a WP-CLI command:

  • WP_CLI::add_command( 'my-plugin thing', ... ).
  • Writing a command class method that reads $args / $assoc_args.
  • Running destructive operations (delete, reset, import, purge) from the command line.
  • Returning data or logging progress from a CLI routine.

WP-CLI runs as the system user, often as root on containers or with broad file-system permissions. It has no WordPress current user by default, so current_user_can() does not authorize CLI actions. Arguments are still untrusted input.

Related: see the capability-permission-checks skill for normal web-request authorization and the cron-background-job-security skill for scheduled jobs.

Core principles (and why they matter)

  1. No current_user_can() in CLI by default. There is no logged-in WordPress user.

Either use WP_CLI::launch_self() with a --user flag, explicitly set a user with --user, or perform capability-independent maintenance tasks only.

  1. Sanitize every argument. $args and $assoc_args can come from scripts, CI, or

shell history; treat them as untrusted input.

  1. Use prepared statements for database access. Do not interpolate $args into

$wpdb queries.

  1. Confirm destructive actions. WP_CLI::confirm() stops accidental data loss in

automated runs.

  1. Never print secrets. API keys, tokens, and passwords must not appear in CLI output,

logs, or shell history.

  1. Be explicit about --allow-root. Running as root is common in containers but

dangerous; document it and avoid file ownership surprises.

Step-by-step implementation

  1. Register the command with WP_CLI::add_command() and a clear docblock.
  2. In the command method, validate argument counts and sanitize each value to type.
  3. For destructive commands, call WP_CLI::confirm() unless --yes is passed.
  4. Use $wpdb->prepare() for any dynamic query.
  5. Avoid echo; use WP_CLI::log(), WP_CLI::success(), or WP_CLI::error().
  6. If the command needs a user context, require --user= and load it with

WP_User::get_data_by() / wp_set_current_user().

Common AI mistakes / anti-patterns

Mistake 1 — Interpolating $args into a query

// ❌ Insecure: SQL injection via CLI argument.
$wpdb->query( "DELETE FROM {$wpdb->prefix}my_table WHERE id = {$args[0]}" );
// ✅ Secure: use $wpdb->prepare().
$id = absint( $args[0] );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}my_table WHERE id = %d", $id ) );

Mistake 2 — Assuming an admin user context

// ❌ Insecure: current_user_can is meaningless without --user.
if ( current_user_can( 'manage_options' ) ) {
    update_option( 'my_plugin_key', $value );
}
// ✅ Secure: require --user or gate by filesystem/CLI policy, not web capability.
class My_Plugin_CLI_Command {
    /**
     * Update a setting.
     *
     * ## OPTIONS
     * [--user=]
     * : User to run as.
     */
    public function update_setting( $args, $assoc_args ) {
        if ( isset( $assoc_args['user'] ) ) {
            $user = get_user_by( 'login', $assoc_args['user'] );
            if ( $user ) {
                wp_set_current_user( $user->ID );
            }
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            WP_CLI::error( 'This command requires --user with manage_options capability.' );
        }

        update_option( 'my_plugin_key', sanitize_text_field( $args[0] ) );
        WP_CLI::success( 'Setting updated.' );
    }
}

Mistake 3 — Printing secrets in output

// ❌ Insecure: secret is now in shell history and terminal scrollback.
WP_CLI::log( 'Using API key: ' . $api_key );
// ✅ Secure: log an identifier or redacted value.
WP_CLI::log( 'Using API key ending in: ' . substr( $api_key, -4 ) );

Mistake 4 — Destructive command with no confirmation

// ❌ Risky: a typo in CI wipes data.
public function purge( $args ) {
    $wpdb->query( "TRUNCATE {$wpdb->prefix}my_plugin_logs" );
}
// ✅ Secure: require confirmation unless --yes is passed.
public function purge( $args, $assoc_args ) {
    if ( ! isset( $assoc_args['yes'] ) ) {
        WP_CLI::confirm( 'This will delete all logs. Are you sure?' );
    }
    global $wpdb;
    $wpdb->query( "TRUNCATE {$wpdb->prefix}my_plugin_logs" );
    WP_CLI::success( 'Logs purged.' );
}

Mistake 5 — Trusting associative args without defaults

// ❌ Fragile: missing key causes undefined array warning.
$days = $assoc_args['days'];
// ✅ Secure: provide defaults and sanitize.
$days = isset( $assoc_args['days'] ) ? absint( $assoc_args['days'] ) : 30;

Correct code examples

A complete secure WP-CLI command class is in [references/secure-wp-cli-command.php](references/secure-wp-cli-command.php).

Checklist

  • [ ] Every CLI argument is sanitized to its expected type.
  • [ ] Database queries use $wpdb->prepare(); no argument interpolation.
  • [ ] Destructive commands call WP_CLI::confirm() unless --yes is provided.
  • [ ] The command does not rely on current_user_can() without an explicit --user.
  • [ ] Secrets, tokens, and API keys are never printed or logged in plaintext.
  • [ ] --allow-root usage is documented and justified.
  • [ ] Output uses WP_CLI::log() / success() / error() instead of echo.
  • [ ] Command docblocks define options and examples.

Official references

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.