T08 · Insecure Dependencies
- Location
references/mcp-integration.md:58- Finding
Unpinned NPM Package Is Downloaded and Executed Through npx
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill does what it says for 2slides presentation generation, but its setup guidance exposes API keys and can run an unpinned MCP package, so users should review it before installing.
Install only if you are comfortable sending presentation text, document-derived content, and reference images to 2slides. Prefer the direct Python scripts or a pinned, reviewed MCP package; avoid putting API keys in URLs when a header or protected secret mechanism is available, and rotate any key that may have been logged or shared.
references/mcp-integration.md:58Unpinned NPM Package Is Downloaded and Executed Through npx
references/mcp-integration.md:28API Credential Is Embedded in the MCP Endpoint Query String
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
print("Generating custom-designed slides...", file=sys.stderr)
print(f"(Timeout set to {timeout}s for {page} page(s))", file=sys.stderr)
response = requests.post(url, headers=headers, json=payload, timeout=timeout)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
print(f"Requesting download for job: {job_id}...", file=sys.stderr)
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# Set reasonable timeout for narration generation
timeout = 120
response = requests.post(url, headers=headers, json=payload, timeout=timeout)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
timeout = 90 if mode == "sync" else 30
print(f"Generating slides in {mode} mode...", file=sys.stderr)
response = requests.post(url, headers=headers, json=payload, timeout=timeout)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
timeout = 90 if mode == "sync" else 30
print(f"Generating slides in {mode} mode...", file=sys.stderr)
response = requests.post(url, headers=headers, json=payload, timeout=timeout)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{API_BASE_URL}/jobs/{job_id}"
print(f"Checking job status: {job_id}...", file=sys.stderr)
response = requests.get(url, headers=headers)
response.raise_for_status()
result = response.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{API_BASE_URL}/themes/search"
print(f"Searching themes{f': {query}' if query else ''}...", file=sys.stderr)
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
result = response.json()
The code is related to presentation generation and does use the 2slides API, so the broad domain is accurate. However, the declared description claims several capabilities not present in this code chunk: creating slides from reference images, summarizing documents into presentations, and supporting both synchronous and asynchronous generation modes. The actual script accepts only text content (--content) plus optional free-form design specs, and calls a single create-pdf-slides API endpoint. It does not process files/documents, images, or implement separate async workflows. Therefore the description overstates the implemented behavior enough to count as a mismatch.
There is a clear description-behavior mismatch. The declared purpose centers on creating presentations via 2slides, but this code chunk only downloads assets for an already existing generation job identified by job_id. Its primary purpose is export/retrieval of generated slide pages and voice files, not presentation creation. While related to the same product domain, the implemented behavior is materially different from the declared generation workflow.
The declared description focuses on creating presentations/slides from content via the 2slides API. The actual code does not generate presentations at all; instead, its primary purpose is adding audio narration to already-generated slides. This is a materially different capability and workflow: it requires an existing completed job ID, invokes a narration-specific endpoint, and exposes voice/multi-speaker options that are not described in the skill declaration. Therefore the description does not accurately represent the code's behavior.
This code chunk has a much narrower purpose than the declared description. It does interact with the same 2slides service and is loosely related through theme discovery, but its actual function is limited to searching available themes. There is no slide or deck generation, no document summarization, no image style matching, and no generation workflow at all. Theme selection support is only indirectly represented by theme lookup. Therefore the code does not accurately match the declared primary purpose of presentation generation.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def get_api_key() -> str:
"""Get API key from environment variable."""
api_key = os.environ.get("SLIDES_2SLIDES_API_KEY")
if not api_key:
raise ValueError(
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# 2slides Skills for Claude Code
AI-powered presentation generation using the [2slides API](https://2slides.com). This Claude Code skill enables you to create professional presentations from text content, match reference image styles, or summarize documents into slides.
## Important Links
The README encourages users to upload documents and presentation content to the external 2slides service but does not clearly warn that attached files, text, and image URLs may be transmitted to and processed by a third-party API. This creates a real privacy and data-handling risk because users may submit sensitive internal reports, research papers, or proprietary content without informed consent.
The skill instructs use of environment secrets and outbound network access but does not declare an explicit tool scope such as permissions or allowed-tools. That gap weakens least-privilege controls and makes it harder for the hosting agent to constrain secret access and external data transmission, especially since the skill sends user content to a third-party API.
The trigger language is broad enough to activate on generic presentation-related requests, increasing the chance that sensitive text, documents, or image URLs are routed to this external service unintentionally. In an agent setting, unintended invocation can cause surprise data transfer, unnecessary API spend, and processing of content the user did not explicitly consent to send off-platform.
The skill repeatedly instructs sending user-provided content, documents, and reference image URLs to 2slides but does not provide a clear privacy warning or consent checkpoint. This is dangerous because users may provide confidential business, personal, or copyrighted material without realizing it will be transmitted to an external processor.
Embedding the API key directly in an MCP URL encourages credential exposure through logs, process listings, screenshots, browser history, copied config files, and telemetry systems. URL-based secrets are especially risky because many tools automatically record full request strings, turning a simple setup example into a durable credential leak path.
The API reference instructs callers to send arbitrary user-provided content to a third-party slide-generation service but provides no warning about privacy, confidentiality, or data retention implications. In a skill that may be used on sensitive business documents or internal content, this omission can lead users or integrators to unknowingly exfiltrate proprietary or personal data to an external processor.
The reference-image endpoint accepts image URLs or base64 image data and encourages submission of external or uploaded images without warning that those images are sent to a third-party service for style matching. Reference images often contain sensitive visuals, metadata, internal diagrams, or personal information, so omission of a privacy warning materially increases the risk of unintended disclosure.
No suspicious patterns detected.