Back to skill

Security audit

rapidapi

Security checks for vulnerabilities and agentic risk

Overview

This is a real RapidAPI helper, but it can send the user’s RapidAPI key to non-RapidAPI or caller-chosen hosts by default.

Review before installing. This skill should not be used with a valuable RapidAPI key until non-RapidAPI hosts are disabled by default, arbitrary direct calls are removed or strictly allowlisted, bundled non-RapidAPI templates are verified or removed, and the documentation clearly warns that request data and credentials are sent to external services. Rotate the RapidAPI key if this implementation has already been used with untrusted direct-call input or unverified templates.

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

T09 · Insecure Skill Coding Practices

Error
Location
index.js:13
Finding
RapidAPI credential is forwarded to arbitrary caller-controlled hosts by default<![CDATA[ ## Vulnerability Details **File Location**: `index.js:13-29`, `index.js:122-130`, `lib/engine.js:3-39`, `lib/engine.js:58-63`, `scripts/call.js:34-38`, `config.example.json:1-6` **Vulnerability Type**: Credential disclosure through unrestricted outbound requests **Risk Level**: Critical ### Vulnerable Code `index.js:13-29`: ```js const primaryEnv = options.primaryEnv || "RAPIDAPI_KEY"; const injectedEnv = options.env || {}; const config = options.config || {}; const rapidApiKey = options.apiKey || options.rapidApiKey || config.rapidApiKey || injectedEnv[primaryEnv] || process.env[primaryEnv]; const templatesDir = options.templatesDir || config.templatesDir || "./templates"; const allowNonRapidApiHosts = typeof options.allowNonRapidApiHosts === "boolean" ? options.allowNonRapidApiHosts : typeof config.allowNonRapidApiHosts === "boolean" ? config.allowNonRapidApiHosts : String(process.env.ALLOW_NON_RAPIDAPI_HOSTS || "true").toLowerCase() === "true"; ``` `index.js:122-130`: ```js async function callRapidApiDirect(input) { const meta = { host: input?.host || "unknown", path: input?.path || "unknown", method: input?.method || "unknown" }; try { return await callRapidApi( input, rapidApiKey, allowNonRapidApiHosts, timeoutMs ); ``` `lib/engine.js:3-39`: ```js export async function callRapidApi(input, rapidApiKey, allowNonRapidApiHosts, defaultTimeoutMs) { const method = (input.method || "GET").toUpperCase(); const meta = { host: input.host, path: input.path, method }; if (!input.host || String(input.host).includes("/") || String(input.host).includes(":")) { throw new HttpError(400, "Invalid host"); } if (!input.path || !String(input.path).startsWith("/")) { throw new HttpError(400, "Path must start with '/' "); } if (!allowNonRapidApiHosts) { const host = String(input.host); const isRapidApiHost = host.endsWith(".rapidapi.com") || host.endsWith(".p ...[truncated 3177 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Change the default to deny non-RapidAPI destinations: ```js String(process.env.ALLOW_NON_RAPIDAPI_HOSTS || "false").toLowerCase() === "true"; ``` 2. Change `config.example.json` to set `allowNonRapidApiHosts` to `false`. 3. Bind credential forwarding to an explicit allowlist. Do not add `X-RapidAPI-Key` unless the normalized destination is approved. 4. Prefer an exact, configurable host allowlist over broad suffix matching. 5. Separate generic HTTP calls from RapidAPI calls. Generic calls must not inherit the RapidAPI credential. 6. Restrict or remove the caller-controlled direct-call interface when it is unnecessary. 7. Disable automatic redirect following or manually validate every redirect target before forwarding sensitive headers. 8. Add tests proving that arbitrary hosts and redirected destinations never receive `X-RapidAPI-Key`. 9. Rotate any RapidAPI key used with the affected implementation if untrusted callers could invoke the direct-call interface. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
templates/toktok_user_info.json:1
Finding
Bundled TokTok actions send the RapidAPI credential to a host outside the Skill’s RapidAPI policy<![CDATA[ ## Vulnerability Details **File Location**: `templates/toktok_user_info.json:1-19`, `templates/toktok_user_posts.json:1-25`, `index.js:78-95`, `lib/engine.js:14-21`, `lib/engine.js:32-39` **Vulnerability Type**: Credential disclosure through unsafe bundled endpoint templates **Risk Level**: High ### Vulnerable Code `templates/toktok_user_info.json:1-19`: ```json { "name": "toktok_user_info", "label": "Get TokTok user info", "description": "Fetch public user profile by username", "host": "x.toktokapi.com", "path": "/user/info", "method": "GET", "querySchema": { "username": { "type": "string", "required": true, "description": "TokTok username" } }, "response": { "type": "json", "dataPath": "data" } } ``` `templates/toktok_user_posts.json:1-25`: ```json { "name": "toktok_user_posts", "label": "Get TokTok user posts", "description": "Fetch public posts by username", "host": "x.toktokapi.com", "path": "/user/posts", "method": "GET", "querySchema": { "username": { "type": "string", "required": true, "description": "TokTok username" }, "count": { "type": "number", "required": false, "default": 20, "description": "Number of items" } }, "response": { "type": "json", "dataPath": "data.items" } } ``` `index.js:78-95`: ```js const result = await callRapidApi( { host: action.template.host, path: finalPath, method: action.template.method, query, body, headers, timeoutMs: action.template.timeoutMs, responseType: action.template.response?.type || "json" }, rapidApiKey, allowNonRapidApiHosts, timeoutMs ); ``` `lib/engine.js:14-21`: ```js if (!allowNonRapidApiHosts) { const host = String(input.host); const isRapidApiHost = host.endsWith(".rapidapi.com") || host.endsWith(".p.rapidapi.com") || host === "rapidapi.com"; if (!isRapidApiHost) { throw new HttpError(400, "Non ...[truncated 1973 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove or disable the two `x.toktokapi.com` templates unless the destination’s authorization to receive the key is explicitly established. 2. Do not use a RapidAPI credential for non-RapidAPI services. Use a destination-specific credential mechanism where required. 3. Validate all templates at registry-load time against an explicit host allowlist. 4. Fail initialization when an enabled template violates the configured destination policy. 5. Store credential policy separately from endpoint templates so a template cannot implicitly authorize itself to receive a secret. 6. Add automated tests verifying that every bundled host is approved and that disallowed templates cannot trigger credential-bearing requests. 7. Rotate credentials if these actions were previously invoked and the destination is not trusted. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
lib/engine.js:3
Finding
Documented method and payload-size security controls are not implemented<![CDATA[ ## Vulnerability Details **File Location**: `README.md:143-148`, `lib/engine.js:3-4`, `lib/engine.js:41-51`, `lib/engine.js:58-63`, `scripts/call.js:3-9` **Vulnerability Type**: Missing request validation and resource limits **Risk Level**: Medium ### Vulnerable Code `README.md:143-148`: ```md ## Security defaults - Disallows overriding `X-RapidAPI-Key` - Optional host restriction with `ALLOW_NON_RAPIDAPI_HOSTS=false` - Method allow-list - Body size and timeout limits ``` `lib/engine.js:3-4`: ```js export async function callRapidApi(input, rapidApiKey, allowNonRapidApiHosts, defaultTimeoutMs) { const method = (input.method || "GET").toUpperCase(); ``` `lib/engine.js:41-51`: ```js const hasBody = !["GET", "DELETE"].includes(method); let body = undefined; if (hasBody && input.body !== undefined) { if (typeof input.body === "string" || input.body instanceof Uint8Array) { body = input.body; } else { if (!headers["Content-Type"]) { headers["Content-Type"] = "application/json"; } body = JSON.stringify(input.body); } } ``` `lib/engine.js:58-63`: ```js let response; try { response = await fetch(url.toString(), { method, headers, body, signal: controller.signal }); } finally { clearTimeout(id); } ``` `scripts/call.js:3-9`: ```js function readStdin() { return new Promise((resolve, reject) => { let data = ""; process.stdin.setEncoding("utf8"); process.stdin.on("data", (chunk) => (data += chunk)); process.stdin.on("end", () => resolve(data)); process.stdin.on("error", reject); }); } ``` ### Technical Analysis The README claims a method allowlist and body-size limits, but neither control is implemented. The request method is converted to uppercase and passed directly to `fetch` without checking it against an approved set. This provides broader outbound HTTP capabilities than the documentation represents and permits unexpected methods where accepted by the runtime and destination. Request bod ...[truncated 1479 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a method allowlist before constructing the request: ```js const allowedMethods = new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]); if (!allowedMethods.has(method)) { throw new HttpError(400, "Unsupported HTTP method"); } ``` 2. Set explicit maximum sizes for: - CLI stdin - Serialized request bodies - String and binary request bodies - Response bodies - Imported endpoint JSON 3. Stop reading stdin and reject the operation immediately once the configured byte limit is exceeded. 4. Validate `Content-Length` where available, while also enforcing a streaming byte limit because the header may be absent or inaccurate. 5. Validate timeout values as finite numbers within safe minimum and maximum bounds. 6. Consider streaming large responses rather than buffering them entirely in memory. 7. Update the README so its security claims exactly match implemented controls. 8. Add tests for oversized input, oversized responses, invalid timeout values, and unsupported HTTP methods. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description describes a network/API integration component with action registration and a generic invocation mechanism. The supplied code does not implement any API client behavior, action registration, triggering, or external calls. It only provides a local object-path lookup helper. This is not merely a supporting detail in context because, based on the supplied chunk alone, the code's behavior is materially different from the declared primary purpose.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The README explicitly promotes a universal direct-call entrypoint and even shows configuration with `allowNonRapidApiHosts: true`, but it does not clearly warn that user-supplied parameters may be transmitted to arbitrary third-party services. In an agent setting, this increases the risk of unintended data exfiltration, especially if prompts, secrets, personal data, or internal URLs are passed through ad-hoc API calls without strong host controls or user consent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises use of an environment secret and clearly enables outbound network access to arbitrary RapidAPI hosts, but it does not declare an explicit tool scope such as allowed tools or permissions. That weakens containment and reviewability, making it easier for a broadly invocable skill to exfiltrate data or use credentials in ways the user did not clearly authorize.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill description explains functionality but does not prominently warn users that it sends data to external RapidAPI endpoints and uses an API credential from the environment. That omission can cause users or upstream agents to pass sensitive inputs without understanding that the data will leave the local environment and be transmitted to third-party services.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The example configuration explicitly enables requests to non-RapidAPI hosts, which expands the skill from a constrained RapidAPI client into a generic outbound HTTP caller. In agent contexts, this can enable SSRF-style access to unintended internal or attacker-controlled endpoints and weakens the trust boundary implied by the skill's description.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This file reads an API credential from options or environment variables and uses it to make outbound HTTP requests, including a direct-call wrapper that accepts arbitrary input for the request. There is no confirmation prompt, logging, comment, or docstring in this file warning that the skill will access credentials and transmit request data to external services.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code enables non-RapidAPI hosts by default via `ALLOW_NON_RAPIDAPI_HOSTS || "true"`, which means a supposed RapidAPI client will permit arbitrary external destinations unless explicitly disabled. Combined with dynamic request construction, this broadens the trust boundary and makes outbound request abuse substantially easier.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The exported `callRapidApi` direct entrypoint bypasses the registry/template allowlist and accepts arbitrary request input, enabling callers to choose host, path, method, headers, and payload. In a skill meant to be template-driven, this defeats the main safety boundary and can be abused for SSRF-like outbound access, unintended third-party requests, or use of the bound RapidAPI credential against unreviewed endpoints.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The function places the RapidAPI key into the X-RapidAPI-Key header for every request, which is a credential-bearing operation. There is no visible disclosure in this file explaining that a sensitive API key is attached to outbound requests.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code performs an outbound HTTP request using caller-supplied URL components and headers, which can transmit user or system data to an external service. In this file there is no confirmation prompt, logging, print statement, or comment/docstring warning that the function sends data off-box.

Vague Triggers

Low
Confidence
86% confidence
Finding
The invocation guidance says to prefer this skill whenever a task involves RapidAPI endpoints or template-defined actions, which is broad enough to trigger use in many loosely related situations. Because the skill can make external requests with a credential and includes a universal direct-call entrypoint, over-broad routing increases the chance of unintended data transfer or unreviewed third-party API use.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This code writes a JSON file to disk with fs.writeFile, which is a safety-relevant operation under the code-file warning criteria. Although the script reports success afterward, there is no confirmation prompt and no comment or docstring near the write explaining that running the script will create or overwrite a file in ./templates.

Static analysis

No suspicious patterns detected.