Back to skill

Security audit

Content Repurposer Pro

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it can fetch arbitrary URLs and send fetched or local content to external LLM APIs without strong scoping or confirmation.

Review before installing or running this skill on sensitive material. Use it only with public or non-confidential content, avoid internal or private-network URLs, and be aware that content may be sent to OpenAI or Anthropic using environment API keys and saved locally under an output directory.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/repurpose.js:33
Finding
Arbitrary URL Fetching Enables Server-Side Request Forgery## Vulnerability Details **File Location**: `scripts/repurpose.js`, lines 33-43; invocation at lines 178-181 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```js function httpGet(url) { return new Promise((resolve, reject) => { const u = new URL(url); const mod = u.protocol === 'https:' ? https : require('http'); mod.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, res => { let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d)); }).on('error', reject); }); } ``` The user-controlled URL reaches the function here: ```js if (args.url) { console.log(`🔗 Fetching ${args.url}...`); const html = await httpGet(args.url); content = extractText(html); } ``` ### Technical Analysis The `--url` command-line argument is passed directly to `httpGet`. The implementation does not apply a hostname allowlist, resolve and validate destination IP addresses, or reject loopback, private, link-local, and reserved network ranges. It also lacks connection and response timeouts and does not impose a response-size limit. Consequently, anyone able to control the command-line argument can instruct the process to issue HTTP requests from the host on which the skill runs. The request therefore inherits that host's network reachability and may access endpoints that are unavailable to an external attacker. The response is passed through `extractText` and subsequently submitted to OpenAI or Anthropic. This creates a potential secondary disclosure path in which information retrieved from an internal endpoint is transmitted to an external LLM service. ### Attack Path 1. An attacker or untrusted caller supplies a URL such as a loopback address, private network host, or cloud link-local metadata endpoint through `--url`. 2. `parseArgs` stores the value in `args.url`. 3. `main` passes the value directly to `httpGet` ...[truncated 1028 chars]
Remediation
## Remediation Suggestions 1. Accept only explicitly supported protocols, preferably HTTPS. 2. Use an explicit allowlist of trusted source domains where operationally possible. 3. Resolve the hostname before connecting and reject every address in loopback, private, link-local, multicast, unspecified, and reserved ranges for both IPv4 and IPv6. 4. Ensure the validated IP is the address used for the connection to reduce DNS-rebinding and time-of-check/time-of-use risks. 5. If redirect support is later added, validate the protocol, hostname, and resolved destination again for every redirect. 6. Apply strict connection, read, and total-request timeouts. 7. Enforce a maximum response size while streaming rather than collecting an unlimited response before truncating extracted text. 8. Restrict accepted content types to expected textual formats. 9. Run the skill in a sandbox with outbound network restrictions that block internal and metadata networks. 10. Warn users before externally transmitting fetched content and avoid sending sensitive internal data to LLM providers.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/repurpose.js:158
Finding
Untrusted Source Content Is Passed to the LLM Without Prompt-Injection Defenses## Vulnerability Details **File Location**: `scripts/repurpose.js`, lines 158-162 **Vulnerability Type**: Indirect Prompt Injection **Risk Level**: Medium ### Vulnerable Code ```js const result = await generateWithLLM( `Repurpose the following content:\n\n${content}`, FORMAT_PROMPTS[fmt] ); results[fmt] = result; ``` ### Technical Analysis Content obtained from a remote URL, local file, or standard input is interpolated directly into the LLM user message. The prompt does not explicitly state that instructions contained in the source are untrusted data, and the source is not placed in a structured data field or strongly delimited from the operational instruction. A malicious document can contain prompt-like text directing the model to disregard the repurposing request and instead generate attacker-selected content. Although the platform formatting rules are supplied as a system message and therefore have higher priority, LLM behavior is probabilistic, and untrusted instructions inside the user message can still influence the result. Generated content is written directly to Markdown files and printed to stdout without validation. There is no review gate, link allowlist, or check that the response follows the selected format. ### Attack Path 1. An attacker publishes or supplies an article containing concealed or visible instructions aimed at the LLM. 2. A user processes the article through `--url`, `--file`, or standard input. 3. The entire source text is appended directly to the user prompt. 4. The LLM interprets some of the embedded source text as instructions rather than merely as content to summarize. 5. The model generates attacker-influenced text, such as deceptive links, fabricated claims, unwanted promotion, or instructions to the end user. 6. The script saves the response to files under the output directory and displays it on stdout. 7. If a user later publishes the generated material without review ...[truncated 750 chars]
Remediation
## Remediation Suggestions 1. Add a strong system-level instruction that source documents are untrusted data and that any instructions, requests, links, or role declarations inside them must not be followed. 2. Place source content inside clear delimiters and state that the model may only extract and transform facts from within those delimiters. 3. Prefer structured API inputs or document fields that separate task instructions from source data where supported. 4. Validate every generated response against format-specific requirements, including maximum length, expected structure, and permitted link destinations. 5. Detect or flag unexpected URLs, calls to action, credential requests, and claims not supported by the source. 6. Require explicit human approval before generated material is published or passed to another automated system. 7. Preserve provenance so reviewers can compare generated claims and links against the original source. 8. Do not add tool execution, automatic posting, or privileged actions to this generation step without separate authorization and policy enforcement.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill advertises operational behavior that may involve code capabilities and access to environment-derived configuration, but it does not declare any explicit tool scope or permissions boundary. That creates ambiguity about what the agent may access or invoke at runtime, increasing the chance of unintended secret exposure or over-broad execution when repurposing content from URLs, files, or pipelines.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The 'Use when' language is broad enough to match many ordinary writing or summarization tasks, which can cause the skill to activate outside the user's intended scope. In this skill, that matters because activation may lead to fetching URLs, reading files, transforming data, and potentially saving or sending outputs, so over-triggering expands the chance of unintended data handling.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill states that outputs may be saved to files or sent directly via APIs, but the description does not prominently warn users about those side effects before activation. This can lead to silent persistence or external transmission of user-provided content, including unpublished drafts, proprietary material, or sensitive transcripts, especially because the skill accepts URLs, local files, and stdin.

External Transmission

Medium
Category
Data Exfiltration
Content
const anthropicKey = process.env.ANTHROPIC_API_KEY;

  if (openaiKey) {
    const res = await httpPost('https://api.openai.com/v1/chat/completions', {
      model: 'gpt-4o-mini',
      messages: [
        { role: 'system', content: systemPrompt },
Confidence
93% confidence
Finding
This code sends user-supplied content to the OpenAI API, which is an external network transmission of potentially sensitive data. In this skill's context, external transmission is expected for functionality, but it is still security-relevant because the tool accepts arbitrary local or piped input and does not enforce minimization, classification, or consent controls.

External Transmission

Medium
Category
Data Exfiltration
Content
}

  if (anthropicKey) {
    const res = await httpPost('https://api.anthropic.com/v1/messages', {
      model: 'claude-3-5-haiku-20241022',
      max_tokens: 2000,
      system: systemPrompt,
Confidence
93% confidence
Finding
This code sends user-supplied content to the Anthropic API, creating the same external data exposure risk as the OpenAI path. Although this is core to the feature, the absence of safeguards means sensitive content from files, URLs, or stdin may leave the local environment without adequate user awareness or policy checks.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script ingests content from a URL, local file, or stdin and forwards that content to an external LLM provider without any explicit consent prompt, warning, or redaction step. This creates a real confidentiality risk because users may unknowingly send proprietary, personal, or otherwise sensitive material to third-party APIs.

Static analysis

No suspicious patterns detected.