Back to skill

Security audit

Podfetcher Tools

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do what it claims, but it needs Review because a Podfetcher API key can be sent to custom or non-HTTPS endpoints without a strong guard or warning.

Install only if you are comfortable sending podcast searches, show IDs, episode IDs, and transcript requests to Podfetcher or to the endpoint you configure. Prefer PODFETCHER_API_KEY through a protected environment or secret manager, avoid --api-key and checked-in MCP config secrets, and do not set PODFETCHER_BASE_URL or --base-url unless the destination is trusted and uses HTTPS. Rotate the key if it may have been exposed.

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
src/sdk.js:36
Finding

API Key Forwarding to Arbitrary or Plaintext Endpoints

Content
View full analysis

Vulnerability Details

File Location: src/sdk.js:36-38, 54-65, 71-77
Vulnerability Type: Unrestricted credential forwarding
Risk Level: Medium

Vulnerable Code

js
export function createPodfetcherClient(options = {}) {
  const baseUrl = options.baseUrl || process.env.PODFETCHER_BASE_URL || DEFAULT_BASE_URL;
  const apiKey = options.apiKey ?? process.env.PODFETCHER_API_KEY;
  const apiKeyHeader = options.apiKeyHeader || process.env.PODFETCHER_API_KEY_HEADER || DEFAULT_API_KEY_HEADER;
  const timeoutMs = parsePositiveInt(options.timeoutMs, DEFAULT_TIMEOUT_MS);
js
const method = requestOptions.method || "GET";
const url = new URL(path, ensureTrailingSlash(baseUrl));
appendQuery(url, requestOptions.query || {});

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

const headers = {
  Accept: "application/json",
  [apiKeyHeader]: apiKey,
};
js
response = await fetch(url, {
  method,
  headers,
  body:
    requestOptions.body === undefined
      ? undefined
      : JSON.stringify(requestOptions.body),
  signal: controller.signal,
});

Technical Analysis

Sending the Podfetcher API key to the default https://api.podfetcher.com endpoint is necessary for the Skill's declared podcast-search and transcript-fetching functionality. The credential handling therefore does not, by itself, constitute covert exfiltration.

However, the client accepts an arbitrary baseUrl through SDK options, PODFETCHER_BASE_URL, or the CLI/MCP --base-url option. It does not validate the destination hostname or require HTTPS before attaching the API key header. As a result, the production credential may be forwarded to an attacker-controlled origin or transmitted over plaintext HTTP.

The behavior exceeds minimum privilege because a credential intended for Podfetcher is automatically delegated to any configured network destination without an explicit unsafe-development opt-in or origin ...[truncated 2006 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require the https: protocol for all remote endpoints.
  2. Allow plaintext HTTP only for explicitly recognized loopback development destinations, such as localhost, 127.0.0.1, or ::1, and only after an explicit opt-in.
  3. Default to an origin allowlist containing https://api.podfetcher.com.
  4. Require a clearly named option such as allowCredentialForwardingToCustomOrigin before attaching an API key to any non-default origin.
  5. Reject URLs containing embedded username/password credentials.
  6. Consider requiring separate non-production credentials whenever a custom endpoint is configured.
  7. Warn users prominently that changing PODFETCHER_BASE_URL changes the recipient of the API key.
  8. Add tests confirming that credentials are not sent to HTTP endpoints or unapproved origins.

Example hardening logic:

js
const url = new URL(baseUrl);
const isDefaultOrigin = url.origin === "https://api.podfetcher.com";
const isLoopback =
  url.hostname === "localhost" ||
  url.hostname === "127.0.0.1" ||
  url.hostname === "::1";

if (url.protocol !== "https:" && !isLoopback) {
  throw new Error("Refusing to send credentials over a non-HTTPS connection");
}

if (!isDefaultOrigin && !options.allowCredentialForwardingToCustomOrigin) {
  throw new Error(
    "Explicit approval is required before forwarding an API key to a custom origin",
  );
}

Additionally, discourage use of --api-key because command-line arguments may appear in process listings or shell history. Prefer environment variables, protected credential stores, or secure standard-input mechanisms.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- SDK import: `./src/sdk.js`

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill declares required environment variables and uses networked functionality, but it does not define an explicit tool scope such as permissions or allowed-tools. That creates an authorization/expectation gap: an agent or user may invoke a skill with broader runtime capabilities than are clearly disclosed, increasing the chance of unintended external requests or access to sensitive environment-backed credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI accepts an API key via the --api-key command-line flag, which can expose the secret through shell history, process listings, job control logs, and orchestration metadata visible to other local users or monitoring systems. In an MCP/server context this is especially risky because the process may be long-lived and launched by tooling that records invocation arguments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This markdown file includes examples and configuration guidance for supplying PODFETCHER_API_KEY, including --api-key and MCP config usage, but it provides no user warning about credential exposure risks. Passing secrets on command lines or storing them in config snippets can leak via shell history, process listings, or checked-in files, so a brief warning would improve user safety.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill explains how to search shows and fetch transcripts but does not clearly warn that user-supplied podcast queries, show IDs, and episode IDs are transmitted to the external Podfetcher service. This is a real transparency and privacy issue because users or downstream agents may assume operations are local when they actually disclose input data to a third party.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.