Back to skill

Security audit

WeChat Official Accounts Keyword Search API

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent single-purpose JustOneAPI WeChat search skill, with a real but disclosed credential-handling risk from passing the API token in process arguments and URL query parameters.

Use this only if you trust JustOneAPI and are comfortable with JUST_ONE_API_TOKEN being sent to api.justoneapi.com as a URL query parameter. Prefer a limited, rotatable token, avoid shell tracing or logging full commands/URLs, and rotate the token if it may have appeared in process monitoring or server logs.

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
bin/run.mjs:220
Finding

API Access Token Exposed Through Process Arguments and URL Query Parameters

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:47, SKILL.md:55; bin/run.mjs:111-117, bin/run.mjs:220-230, bin/run.mjs:258-267
Vulnerability Type: Sensitive credential exposure
Risk Level: Medium

The documented invocation passes the API token as a command-line argument:

bash
node {baseDir}/bin/run.mjs --operation "searchWeixinV1" --token "$JUST_ONE_API_TOKEN" --params-json '{"keyword":"<keyword>"}'

The helper subsequently injects that token into the request parameters:

js
function injectToken(operation, params, cliToken) {
  const tokenParam = operation.parameters.find((parameter) => parameter.name === "token");
  if (!tokenParam || params.token !== undefined) {
    return;
  }
  if (!cliToken) {
    fail("--token is required for this operation.", {
      operationId: operation.operationId,
    });
  }
  params.token = cliToken;
}

Because the manifest defines token as a query parameter, applyQueryParams places the credential in the URL:

js
function applyQueryParams(operation, params, url) {
  for (const parameter of operation.parameters.filter((item) => item.location === "query")) {
    const value = params[parameter.name];
    if (value === undefined) {
      continue;
    }
    appendValue(url.searchParams, parameter.name, value);
  }
}

function appendValue(searchParams, name, value) {
  if (Array.isArray(value)) {
    for (const item of value) {
      appendValue(searchParams, name, item);
    }
    return;
  }
  if (value && typeof value === "object") {
    searchParams.append(name, JSON.stringify(value));
    return;
  }
  searchParams.append(name, String(value));
}

The resulting URL is then sent to the fixed JustOneAPI HTTPS endpoint:

js
let response;
try {
  response = await fetch(url, requestInit);
} catch (error) {
  fail("Network request failed.", {
    cause: error
...[truncated 2343 chars]
Remediation
View remediation

Remediation Suggestions

  1. Read the token directly from process.env.JUST_ONE_API_TOKEN inside the Node.js process instead of requiring a --token argument.
  2. Remove or deprecate the CLI token option so credentials do not appear in process listings or process telemetry.
  3. If JustOneAPI supports header-based authentication, send the token through an Authorization header rather than a query parameter:
    js
    const token = process.env.JUST_ONE_API_TOKEN;
    if (!token) {
      fail("JUST_ONE_API_TOKEN is required.");
    }
    
    const requestInit = {
      method: operation.method,
      headers: {
        accept: "application/json",
        authorization: `Bearer ${token}`,
      },
    };
    
  4. If the upstream API mandates query-string authentication, ensure the helper never prints the complete request URL. Configure gateways, proxies, servers, tracing systems, and error-reporting tools to redact the token parameter.
  5. Restrict access to network and process telemetry, minimize log retention, and prevent shell tracing around credential-bearing commands.
  6. Update SKILL.md to document environment-only credential loading rather than command-line token passing.
  7. Rotate any token that may previously have appeared in process monitoring or URL logs, and use narrowly scoped, short-lived credentials where supported.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The API requires an access token to be sent as a query parameter, which is an insecure credential handling pattern because query strings are commonly logged by clients, proxies, servers, analytics tools, and browser history. This increases the chance of token disclosure and subsequent unauthorized API use if logs or URLs are exposed.

Content

Scanner excerpt · generated/operations.json (reported line 15)May include surrounding context.

json
"parameters": [
        {
          "defaultValue": null,
          "description": "Access token for the API.",
          "enumValues": [],
          "location": "query",
          "name": "token",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · bin/run.mjs (reported line 20)May include surrounding context.

js
| Name | In | Required | Type | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `token` | `query` | yes | `string` | n/a | Access token for the API. |
| `keyword` | `query` | yes | `string` | n/a | The search keyword. |
| `offset` | `query` | no | `integer` | `0` | Pagination offset (starts with 0, increment by 20). |
| `searchType` | `query` | no | `string` | `_0` | Type of search results (accounts, articles, etc.).

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · generated/operations.md (reported line 19)May include surrounding context.

md
| Name | In | Required | Type | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `token` | `query` | yes | `string` | n/a | Access token for the API. |
| `keyword` | `query` | yes | `string` | n/a | The search keyword. |
| `offset` | `query` | no | `integer` | `0` | Pagination offset (starts with 0, increment by 20). |
| `searchType` | `query` | no | `string` | `_0` | Type of search results (accounts, articles, etc.).

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill invokes a network-capable helper (node {baseDir}/bin/run.mjs calling a remote API) but does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization and transparency gap: an agent/runtime may permit broader tool use than intended, making external requests without clear least-privilege boundaries or user-visible constraints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill defines the API token as a query parameter and later appends all query parameters directly to the request URL. Query-string credentials are routinely exposed through logs, browser/history tooling, reverse proxies, monitoring systems, and error traces, making accidental token disclosure more likely even when HTTPS is used.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This manifest describes the skill generically as searching WeChat content 'with keyword' but does not define narrow activation phrases, scope limits, or exclusion conditions. For a manifest file, that lack of specificity can create ambiguous invocation behavior and unintended triggering from ordinary search-related requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation requires an API access token to be sent in the URL query string, which is commonly logged by browsers, proxies, server access logs, monitoring tools, and shared via referrers. Even though this is only API documentation, normalizing token transport in query parameters increases the likelihood of credential exposure during routine use.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.secret_argv_exposure

Instructions pass high-value credentials through process argv.

Critical
Code
suspicious.secret_argv_exposure
Location
SKILL.md:46