Back to skill

Security audit

WooCommerce Stock Monitor

Security checks for vulnerabilities and agentic risk

Overview

This stock-monitoring skill is mostly purpose-aligned, but it can send WooCommerce API credentials over plaintext HTTP if configured with an insecure store URL.

Review this before installing. Use only a read-only WooCommerce API key, ensure the configured store URL is HTTPS, protect the credentials file, and avoid running the cron job until the script enforces HTTPS for authenticated WooCommerce requests.

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

Error
Location
scripts/stock-monitor.js:12
Finding

WooCommerce API Credentials May Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/stock-monitor.js, lines 12–13, 19–21, 25–27, and 42–44
Vulnerability Type: Insecure transmission of reusable API credentials
Risk Level: High

Vulnerable Code

js
const https = require('https');
const http = require('http');

function wooCfg() {
  const cfg = JSON.parse(fs.readFileSync(WOO_API_PATH, 'utf8'));
  const auth = Buffer.from(`${cfg.consumer_key}:${cfg.consumer_secret}`).toString('base64');
  return { base: cfg.url, auth };
}

function httpGet(url, headers = {}) {
  return new Promise((resolve, reject) => {
    const mod = url.startsWith('https') ? https : http;
    mod.get(url, { headers }, (res) => {
      let data = '';
      res.on('data', d => data += d);
      res.on('end', () => {
        try { resolve(JSON.parse(data)); }
        catch(e) { reject(new Error(`Parse error: ${data.slice(0,200)}`)); }
      });
    }).on('error', reject);
  });
}

async function fetchAllProducts(base, auth) {
  const products = [];
  let page = 1;
  while (true) {
    const url = `${base}/wp-json/wc/v3/products?per_page=100&page=${page}&status=publish`;
    const batch = await httpGet(url, { 'Authorization': `Basic ${auth}` });

Technical Analysis

The store URL comes from woo-api.json and is not validated to require HTTPS. The request helper selects Node.js's plaintext http module whenever the resulting URL does not start with https.

At the same time, the WooCommerce consumer key and consumer secret are concatenated and Base64-encoded for an HTTP Basic Authentication header. Base64 provides no confidentiality. If cfg.url uses http://, the reusable credentials are transmitted without transport encryption and can be read by a network-positioned attacker.

Configuration tampering can also redirect requests to an attacker-controlled endpoint. Because the authorization header is sent to the configured destinatio ...[truncated 1713 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the configured store address with new URL(cfg.url) and reject it unless protocol === 'https:'.
  2. Validate the hostname against the expected WooCommerce store hostname or a narrowly defined allowlist before constructing the authorization header.
  3. Remove plaintext HTTP fallback for authenticated WooCommerce requests and fail closed on invalid or unsupported URL schemes.
  4. Normalize and validate the base URL before appending API paths.
  5. Continue using a dedicated read-only WooCommerce API key with only the permissions required to retrieve product stock data.
  6. Document HTTPS as mandatory rather than merely showing it in the configuration example.
  7. Protect woo-api.json with restrictive filesystem permissions and rotate credentials if they may previously have been used over HTTP.
  8. Consider rejecting redirects or validating every redirect destination so credentials cannot be forwarded to an unexpected host.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 17)May include surrounding context.

md
node scripts/stock-monitor.js

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill requires access to environment variables for sensitive values such as the Telegram bot token and WooCommerce credentials path, but it does not declare any explicit tool scope or permission boundary. This weakens reviewability and containment because the runtime can access secrets without the manifest clearly stating that capability, increasing the chance of unintended secret exposure or over-privileged execution.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
55% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/stock-monitor.js (reported line 83)May include surrounding context.

js
process.exit(1);
  }

  // Load previous state
  let prevState = {};
  if (fs.existsSync(STATE_FILE)) {
    prevState = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));

Static analysis

No suspicious patterns detected.