Back to skill

Security audit

WordPress REST API CLI

Security checks for vulnerabilities and agentic risk

Overview

This WordPress CLI appears legitimate, but it needs Review because it can change or delete live site content and may send WordPress credentials over non-HTTPS if misconfigured.

Install only if you are comfortable giving this CLI WordPress API credentials that can create, edit, and delete site content. Use a dedicated low-privilege application password, configure only an HTTPS WP_BASE_URL, prefer drafts or staging first, and treat delete and raw request commands as live-site operations.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/wp-cli.js:55
Finding
WordPress credentials may be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wp-cli.js:42-61, 87-96` **Vulnerability Type**: Missing HTTPS enforcement for authenticated network requests **Risk Level**: Medium ### Vulnerable Code Credential-bearing authorization headers are generated from environment variables: ```javascript function buildAuthHeader() { const basicToken = process.env.WP_BASIC_TOKEN; if (basicToken) { return { Authorization: `Basic ${basicToken}` }; } const user = process.env.WP_USER; const appPassword = process.env.WP_APP_PASSWORD; if (user && appPassword) { const token = Buffer.from(`${user}:${appPassword}`).toString('base64'); return { Authorization: `Basic ${token}` }; } const jwt = process.env.WP_JWT_TOKEN; if (jwt) { return { Authorization: `Bearer ${jwt}` }; } return {}; } function resolveBaseUrl() { const base = process.env.WP_BASE_URL; if (!base) { console.error('Missing WP_BASE_URL. Example: https://example.com'); process.exit(1); } return base.replace(/\/$/, ''); } ``` These headers are subsequently attached to requests without checking the URL protocol: ```javascript async function requestJson({ method, path, query, body }) { const headers = { 'Accept': 'application/json', ...buildAuthHeader(), }; const options = { method, headers }; if (body !== undefined) { headers['Content-Type'] = 'application/json'; options.body = JSON.stringify(body); } const response = await fetch(buildApiUrl(path, query), options); ``` ### Technical Analysis `resolveBaseUrl()` accepts any value supported by the `URL` and `fetch` implementations, including an `http://` URL. No runtime control requires HTTPS before `requestJson()` attaches a Basic or Bearer authorization header. Base64 encoding in HTTP Basic authentication does not provide encryption. If `WP_BASE_URL` uses HTTP, a network-positioned attacker can observe the authorization header, request body, query parameters, and ...[truncated 2307 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse and validate `WP_BASE_URL` before any request is made, and reject protocols other than HTTPS: ```javascript function resolveBaseUrl() { const rawBase = process.env.WP_BASE_URL; if (!rawBase) { throw new Error('Missing WP_BASE_URL. Example: https://example.com'); } let baseUrl; try { baseUrl = new URL(rawBase); } catch { throw new Error('WP_BASE_URL must be a valid absolute URL.'); } if (baseUrl.protocol !== 'https:') { throw new Error('WP_BASE_URL must use HTTPS.'); } baseUrl.hash = ''; baseUrl.search = ''; baseUrl.pathname = baseUrl.pathname.replace(/\/+$/, ''); return baseUrl.toString().replace(/\/$/, ''); } ``` 2. If local plaintext testing is required, permit it only through an explicit opt-in such as `WP_ALLOW_INSECURE_HTTP=true`, restrict the exception to loopback hosts, and print a prominent warning. Production deployments should never enable this option. 3. Validate that the final request URL remains on the configured origin before attaching credentials. Build unauthenticated and authenticated requests separately so authorization headers cannot accidentally be sent to an unintended destination. 4. Use a dedicated WordPress application password for a least-privileged service account. Avoid Administrator credentials unless the workflow strictly requires them. 5. Rotate the application password, Basic token, or JWT immediately if it may previously have been used with an HTTP endpoint. 6. Add automated tests asserting that: - `http://example.com` is rejected. - Malformed and non-HTTP(S) URLs are rejected. - HTTPS URLs are accepted. - Authorization headers are never attached when transport validation fails. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- Get: `GET /posts/{id}`
- Create: `POST /posts`
- Update: `POST /posts/{id}`
- Delete: `DELETE /posts/{id}`

Common fields:
- `title`, `content`, `excerpt`
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- Get: `GET /pages/{id}`
- Create: `POST /pages`
- Update: `POST /pages/{id}`
- Delete: `DELETE /pages/{id}`

### Categories
- List: `GET /categories`
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises and operationally requires access to environment variables for credentials and network access to a WordPress instance, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap where the runtime may grant broader capabilities than reviewers or orchestrators expect, increasing the risk of unintended outbound requests or secret access.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file documents create, update, and delete operations for WordPress posts, including `DELETE /posts/{id}`, but does not warn users that these actions modify or remove live site content. For markdown files, safety-affecting behaviors that impact user data or system integrity should include a clear warning.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The guide lists write operations for pages, including deletion, but provides no caution that these requests can alter or permanently remove website pages. In markdown skill documentation, such behaviors should be disclosed because they can affect user data and site integrity.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code exposes `posts:delete` and `pages:delete` operations that perform irreversible remote deletions via HTTP DELETE, but there is no confirmation prompt, warning message, or explanatory comment/docstring disclosing that user content will be removed. For code files, destructive operations should have some visible disclosure unless clearly warned elsewhere, and no such warning is present in this file.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The `request` command allows arbitrary HTTP methods, paths, and optional JSON bodies to be transmitted to the configured WordPress server, but the code provides no user-facing notice that supplied data will be sent over the network. Although network access is central to this CLI, this generic passthrough operation is broad enough that an explicit warning would help users understand that arbitrary payloads may be transmitted to the remote site.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/wp-cli.js:48