Back to skill

Security audit

WeChat Official Accounts Article Comments API

Security checks for vulnerabilities and agentic risk

Overview

This is a narrow JustOneAPI wrapper, but it sends the API token in the URL query string, which can expose credentials through logs or monitoring systems.

Install only if you are comfortable using a JustOneAPI token in a URL query parameter. Prefer a short-lived, tightly scoped token, avoid sharing logs or full request URLs, and review privacy obligations before collecting commenter details from WeChat articles.

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:216
Finding

API Credential Exposed in URL Query String

Content
View full analysis

Vulnerability Details

File Location: bin/run.mjs:25-31, bin/run.mjs:56-76, and bin/run.mjs:216-223
Vulnerability Type: API credential disclosure through URL query parameters
Risk Level: Medium

Vulnerable Code

The operation manifest defines the access token as a query parameter:

js
{
  "defaultValue": null,
  "description": "Access token for the API.",
  "enumValues": [],
  "location": "query",
  "name": "token",
  "required": true,
  "schemaType": "string"
}

The token is injected into the request parameters and subsequently added to the URL:

js
const params = parseParams(args.paramsJson);
applyDefaults(operation, params);
injectToken(operation, params, args.token);
validateRequired(operation, params);

const baseUrl = manifest.baseUrl;
const url = new URL(operation.path, ensureBaseUrl(baseUrl));
applyPathParams(operation, params, url);
applyQueryParams(operation, params, url);

const requestInit = {
  headers: {
    "accept": "application/json",
  },
  method: operation.method,
};

response = await fetch(url, requestInit);

The query-parameter helper serializes every parameter whose location is query, including the token:

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);
  }
}

Technical Analysis

Authentication is necessary for the Skill's declared functionality, and the credential is sent over HTTPS only to the declared endpoint at https://api.justoneapi.com. Therefore, the network request itself is expected and there is no evidence of covert exfiltration.

However, placing an API credential in the URL produces a request resembling:

text
https://api
...[truncated 2109 chars]
Remediation
View remediation

Remediation Suggestions

  1. Change the API authentication contract to use an HTTP authorization header rather than a query parameter, for example:

    js
    const requestInit = {
      method: operation.method,
      headers: {
        accept: "application/json",
        authorization: `Bearer ${args.token}`,
      },
    };
    
  2. Remove token from operation.parameters so that generic query serialization cannot place it in the URL.

  3. Reject a token property supplied through --params-json; credentials should enter through one dedicated authentication channel.

  4. Prefer reading the token directly from JUST_ONE_API_TOKEN rather than requiring it as a command-line argument. Command-line arguments may be visible to local process-inspection tools or retained in shell history.

  5. If the upstream API cannot support header-based authentication:

    • Use short-lived, narrowly scoped tokens.
    • Ensure servers, proxies, gateways, and telemetry systems redact the token query parameter.
    • Disable storage of complete query strings where operationally possible.
    • Rotate affected credentials and monitor for unauthorized usage.
    • Avoid including complete request URLs in errors or diagnostic logs.
  6. Add automated tests confirming that secrets never appear in generated URLs, stdout, stderr, or exception payloads.

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 (8)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

This finding is substantiated by the skill's handling of an access token as an externally supplied credential and placing it into the URL query string. While the code does not exfiltrate the token to an unrelated destination, it does increase credential exposure risk because the secret is transmitted in a less safe channel.

Content

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

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

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 dangerous because query strings are commonly logged by clients, proxies, gateways, browser history, and monitoring systems. Exposure of this token could allow unauthorized use of the third-party API and compromise associated account access or quota.

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
90% confidence
Finding

Requiring an access token in a query parameter is risky because query strings are commonly logged by servers, proxies, browser history, analytics tooling, and monitoring systems. This can expose the token to unintended parties and enable unauthorized API access if logs or URLs are leaked.

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. |
| `articleUrl` | `query` | yes | `string` | n/a | The URL of the Weixin article. |

### Request body

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill invokes a network-capable helper (node {baseDir}/bin/run.mjs) that can call an external API, but the manifest does not declare any explicit tool scope such as permissions or allowed-tools. This weakens policy enforcement and transparency, because an agent or reviewer cannot easily determine from the skill declaration that outbound network access is required and permitted.

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 automatically appends it to the request URL. Query-string credentials are commonly exposed through logs, browser/history equivalents, proxy caches, monitoring systems, and upstream infrastructure, making accidental credential disclosure more likely than if the token were sent in an Authorization header.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The operation description explicitly states it retrieves commenter details, comment text, and timestamps from a third-party API, but provides no privacy, consent, or data-handling warning. Because this skill facilitates collection of potentially personal data from social platform users, the omission can lead downstream users to process personal data without understanding legal, policy, or minimization obligations.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This manifest-like file describes the API operation and skill name but provides no explicit trigger phrases, activation constraints, or exclusion conditions. For manifest files, the lack of specificity about when the skill should be invoked can lead to overly broad or unintended activation by an agent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The natural-language descriptions and tags indicate the skill is specifically for WeChat/Weixin Official Accounts content, which implies a locale/platform constraint. The file does not state that this is region-specific by design or offer any user choice, which can be interpreted as a language/locale policy concern under the stated rule.

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:41