Back to skill

Security audit

Larry Marketing

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real social marketing automation skill, but it needs Review because it handles posting credentials, revenue data, recurring jobs, and third-party installs with weak safeguards.

Only install after reviewing the posting scope and using least-privilege API keys. Keep config.json and generated reports out of source control, prefer environment variables or a secret manager, review any RevenueCat access carefully, pin installs where possible, and require explicit confirmation before public posting or recurring scheduled jobs.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate-slides.js:137
Finding
Replicate API Token Disclosure Through an Unvalidated Polling URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-slides.js`, lines 137-139 **Vulnerability Type**: Credential disclosure through a response-controlled URL **Risk Level**: High ### Vulnerable Code ```javascript const pollRes = await fetch(prediction.urls.get, { headers: { 'Authorization': `Token ${apiKey}` } }); prediction = await pollRes.json(); ``` ### Technical Analysis The script obtains `prediction.urls.get` from the Replicate API response and uses it directly as the destination of an authenticated request. It does not verify: - That the URL uses HTTPS. - That the hostname belongs to Replicate. - That the URL does not resolve to a private or loopback address. - That redirects remain within an approved Replicate domain. The request includes the user's Replicate API token in the `Authorization` header. Consequently, a compromised, intercepted, or malformed API response could supply an attacker-controlled polling URL and cause the script to transmit the token to that endpoint. Although the initial prediction request is sent to a hard-coded Replicate HTTPS endpoint, treating a response-provided URL as trusted creates a credential-forwarding vulnerability. ### Attack Path 1. The user configures the Skill with a valid Replicate API token. 2. The script submits an image-generation request to Replicate. 3. An attacker capable of compromising or influencing the returned prediction object supplies an attacker-controlled value in `prediction.urls.get`. 4. The script calls the supplied URL without validating its origin. 5. The request includes `Authorization: Token <user-token>`. 6. The attacker records the token and uses it to submit predictions or consume the victim's Replicate account quota. ### Impact Assessment Successful exploitation exposes the Replicate API token. An attacker could obtain the privileges assigned to that token, including submitting paid inference jobs, accessing associated API resources, exhausting quotas, or c ...[truncated 190 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Parse `prediction.urls.get` with the standard `URL` class before using it. - Require the `https:` protocol. - Maintain an explicit allowlist of documented Replicate API hostnames. - Reject URLs containing embedded credentials or unexpected ports. - Disable automatic redirects where possible, or validate every redirect target before forwarding credentials. - Never attach the Replicate token to a URL that has not passed origin validation. - Consider constructing the polling endpoint locally from a validated prediction identifier instead of trusting a complete URL from the response. Example hardening pattern: ```javascript function validateReplicateUrl(value) { const url = new URL(value); const allowedHosts = new Set(['api.replicate.com']); if (url.protocol !== 'https:' || !allowedHosts.has(url.hostname)) { throw new Error('Untrusted Replicate polling URL'); } return url.toString(); } const pollingUrl = validateReplicateUrl(prediction.urls.get); const pollRes = await fetch(pollingUrl, { redirect: 'error', headers: { Authorization: `Token ${apiKey}` } }); ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate-slides.js:145
Finding
Server-Side Request Forgery and Resource Exhaustion Through an Unvalidated Image URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-slides.js`, lines 145-148 **Vulnerability Type**: Server-side request forgery and unbounded remote download **Risk Level**: Medium ### Vulnerable Code ```javascript const imageUrl = Array.isArray(prediction.output) ? prediction.output[0] : prediction.output; const imgRes = await fetch(imageUrl); const buf = Buffer.from(await imgRes.arrayBuffer()); fs.writeFileSync(outPath, buf); ``` ### Technical Analysis The final Replicate prediction output is treated as a trusted image URL. The script fetches it without validating its protocol, hostname, resolved address, HTTP status, content type, redirect chain, or response size. This produces several related risks: - A response-controlled URL can target loopback, link-local, or private-network services reachable from the Agent host. - Redirects can lead from an apparently legitimate host to an internal service. - `arrayBuffer()` buffers the complete response in memory with no size limit, allowing a large or endless response to exhaust memory. - Arbitrary non-image data can be written to a file with a `.png` name because no image signature or decoding validation is performed. - Unlike the OpenAI path, the Replicate image download does not use the configured abort signal. The downloaded bytes are not executed by this script, so this is not a confirmed remote-code-execution issue. The confirmed risks are unauthorized network access and denial of service. ### Attack Path 1. The user runs slide generation with the Replicate provider. 2. An attacker capable of influencing the prediction output supplies a URL such as a loopback, private-network, cloud metadata, or attacker-controlled oversized endpoint. 3. The script calls the URL from the Agent's network environment. 4. For an internal target, the request reaches a service unavailable to the attacker directly. 5. For an oversized target, the script buffers the entire response with `arrayBuffer()`, p ...[truncated 665 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require HTTPS and allowlist expected Replicate media-storage domains. - Resolve the destination hostname and reject loopback, private, link-local, multicast, and reserved address ranges. - Repeat destination validation after every redirect or disable redirects. - Check `imgRes.ok` before reading the body. - Require an approved image content type. - Stream the response to disk while enforcing a conservative byte limit instead of buffering the entire response. - Apply an `AbortController` timeout to the image download. - Validate the resulting file with an image decoder or signature inspection before accepting it. - Remove incomplete output files when validation or download fails. A secure implementation should enforce both origin and size constraints before writing any returned content. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/onboarding.js:43
Finding
API Credentials and RevenueCat Transaction Data Stored in Plaintext Files<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/onboarding.js`, lines 43-60 - `scripts/daily-report.js`, lines 227-230 - `README.md`, lines 48-68 - `SKILL.md`, lines 329-359 **Vulnerability Type**: Insecure storage of secrets and sensitive transaction data **Risk Level**: Medium ### Vulnerable Code The generated configuration explicitly stores provider credentials in an ordinary JSON file: ```javascript const configTemplate = { app: { name: '', description: '', audience: '', problem: '', differentiator: '', appStoreUrl: '', category: '', isMobileApp: false }, imageGen: { provider: '', apiKey: '', model: '' }, uploadPost: { apiKey: '', profile: 'upload_post', platforms: ['tiktok', 'instagram'] }, revenuecat: { enabled: false, v2SecretKey: '', projectId: '' }, ``` The configuration is written without a restrictive file mode: ```javascript const cfgPath = `${dir}/config.json`; if (!fs.existsSync(cfgPath)) { fs.writeFileSync(cfgPath, JSON.stringify(configTemplate, null, 2)); console.log(`📝 Created ${cfgPath}`); } ``` The daily report persists the complete RevenueCat metrics object, which includes the fetched transaction array: ```javascript if (rcMetrics) { fs.writeFileSync(rcSnapshotPath, JSON.stringify({ date: dateStr, ...rcMetrics }, null, 2)); } ``` ### Technical Analysis The documented setup instructs users to place image-generation, Upload-Post, and RevenueCat secret keys directly in `config.json`. The initializer writes the file using default filesystem permissions and does not create or require a `.gitignore` entry. In addition, `getRevenueCatMetrics()` returns `transactions: transactions.items || []`, and the complete object is later written to `rc-snapshot.json`. This retains transaction records even though the report primarily needs aggregate values and timestamps for attribution. The exposure is local rather than a hidden network exfilt ...[truncated 1464 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove API keys and secret keys from `config.json`. - Read credentials from environment variables or a supported operating-system secret store. - Store only non-secret values such as provider names, profile names, project identifiers, and platform selections in configuration. - Create sensitive files with mode `0600` and verify ownership before reading them. - Add `tiktok-marketing/config.json`, `rc-snapshot.json`, analytics snapshots, reports, and other generated state to a supplied `.gitignore`. - Fail validation when literal secret-looking values are found in a repository-tracked configuration file. - Store only aggregate RevenueCat metrics required by the report. - If timestamps are needed for attribution, retain a minimal redacted structure and omit customer identifiers, management URLs, product details, and unrelated transaction fields. - Establish retention limits and delete stale transaction snapshots. - Document key rotation procedures for users who may already have committed or shared configuration files. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:29
Finding
Unpinned Third-Party Installation Commands Create Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Locations**: - `README.md`, lines 29-38 - `SKILL.md`, lines 244-260 - `SKILL.md`, lines 429-449 **Vulnerability Type**: Unpinned third-party dependencies and executable installation tooling **Risk Level**: Medium ### Vulnerable Code and Instructions ```bash # Install as a skill npx skills add Upload-Post/upload-post-larry-marketing-skill ``` ```bash git clone https://github.com/Upload-Post/upload-post-larry-marketing-skill.git cd tiktok-marketing-skill npm install canvas ``` The Skill also recommends installing another Skill with access to sensitive subscription data: ```bash clawhub install revenuecat ``` ### Technical Analysis The installation workflow does not pin immutable package versions, repository commit hashes, or integrity digests. Commands such as `npx` and `npm install` can download packages and execute package lifecycle scripts with the current user's privileges. The RevenueCat Skill is also installed by a mutable name rather than an immutable artifact reference, despite being intended to receive a secret key and broad access to project metrics, customers, subscriptions, offerings, entitlements, and transactions. No malicious package was identified in the audited artifact. The confirmed issue is that the documented installation process does not provide reproducible or integrity-verified dependency resolution, leaving users exposed to future package compromise, account takeover, or unexpected upstream changes. ### Attack Path 1. An attacker compromises an upstream package, publisher account, repository branch, package-resolution path, or named Skill release. 2. The user or Agent runs one of the documented unpinned installation commands. 3. The package manager resolves the mutable name to the compromised version. 4. Installation or lifecycle code executes under the user's account. 5. The malicious dependency reads plaintext configuration credentials, modifies project files, or establishes additional ...[truncated 598 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin all packages and Skills to exact reviewed versions. - Pin Git-based installation to a reviewed commit hash rather than a mutable branch. - Publish and verify cryptographic checksums or signed release artifacts. - Include and enforce a lockfile for Node.js dependencies. - Use reproducible installation commands such as `npm ci` with a committed lockfile. - Review package lifecycle scripts and disable them with `--ignore-scripts` when they are unnecessary. - Verify package publisher identity and repository ownership before installation. - Apply least-privilege API credentials to separately installed integrations. - Review the RevenueCat Skill before granting it a secret key, and use a credential restricted to only the endpoints required for reporting. - Document a controlled update process that requires review before changing pinned versions. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (53)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The description claims a broad end-to-end social media marketing automation system for TikTok and Instagram, including research, generation, posting, analytics, and optimization. The supplied code only implements one narrow sub-function: adding text overlays to six slideshow images on disk. It does not access browsers, external APIs, social platforms, analytics systems, Upload-Post, or RevenueCat, and it does not perform competitor research, posting, or iterative optimization. While text overlay creation is mentioned in the description, the actual code chunk's primary purpose is much narrower and materially different from the declared overall capability set.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description claims an end-to-end social media marketing automation workflow, but this code chunk only implements the analytics/history tracking portion. Its primary behavior is limited to reading Upload-Post analytics and upload history, summarizing post success/failure, and writing a local snapshot file. While analytics tracking is part of the declared description, the actual code does not perform the major advertised functions such as research, generation, overlaying, posting, optimization, or conversion analysis. Therefore the description materially overstates what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents a broad end-to-end social media marketing automation system, but the supplied code only manages a local JSON file for competitor research notes. Its functions are limited to loading/saving competitor data, appending a competitor record, and printing summaries/gap insights. There is no implementation for slideshow creation, image generation, overlay rendering, social posting, analytics, optimization, or conversion tracking. Even the research itself is not performed here; the script says that is done manually/by an agent using the browser. This is a material description-to-behavior mismatch because the code’s primary purpose is much narrower than declared.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The code only implements the analytics/reporting/optimization slice of the declared system. It reads a config file, calls Upload-Post analytics and history endpoints, optionally calls RevenueCat, computes deltas and simple funnel diagnoses, tracks hook performance locally, and writes a report. It does not research competitors, generate images, add overlays, or create/post slideshow content. While the description includes analytics, hook testing, CTA optimization, and RevenueCat-based feedback loops that are partially reflected here, the declared purpose presents a much broader automation skill whose primary user-facing promise is end-to-end slideshow marketing automation and posting. This supplied code chunk is materially narrower and centered on reporting/analysis rather than content production or posting.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a broad social media marketing automation workflow spanning research, creative generation, publishing, analytics, and optimization. The supplied code chunk implements only one narrow subtask: generating six slideshow images (or copying local images) from prompts. It does not interact with TikTok, Instagram, Upload-Post, browsers, analytics systems, or RevenueCat, nor does it perform text overlaying or optimization. While image generation is consistent with one portion of the description, the actual behavior is materially narrower than the declared purpose, so the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description presents an end-to-end social marketing automation system. The supplied code chunk is much narrower: it is an onboarding/config bootstrap and validator script. Its primary purpose is to create folders and empty JSON templates, and to check whether required configuration fields exist. While some file/template names correspond to the described system domains (competitors, strategy, hook performance, Upload-Post, RevenueCat), the code itself does not execute those capabilities. This is a material description-behavior mismatch because the actual behavior is setup validation rather than marketing automation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a broad end-to-end social marketing automation workflow, but the supplied code only implements one small portion of that workflow: uploading existing slideshow images to Upload-Post for multi-platform posting and saving the returned request ID/metadata locally. While the posting portion does align with the description, the script does not perform research, generate images, add overlays, analyze analytics, optimize hooks/CTAs, track conversions, or iterate based on outcomes. Therefore the description materially overstates the actual behavior of this code chunk.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
**Save the agreed prompt style to config as `imageGen.basePrompt`** so every future post uses it.

**Key prompt rules (explain these as they come up, don't lecture):**
- "iPhone photo" + "realistic lighting" = looks real, not AI-generated
- Lock architecture/layout in EVERY slide prompt or each slide looks like a different place
- Include everyday objects (mugs, remotes, magazines) for lived-in feel
Confidence
85% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Ae1

High
Category
analysis-evasion
Content
Task: Run scripts/daily-report.js --config tiktok-marketing/config.json --days 3
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Task: Run scripts/daily-report.js --config tiktok-marketing/config.json --days 3
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill explicitly instructs storing multiple sensitive API keys and secret tokens in a JSON config file, including OpenAI, Upload-Post, and RevenueCat secrets. Plaintext credential storage in project files raises the risk of accidental commit, workspace leakage, unauthorized reuse, and compromise of posting and revenue systems.

Ae1

High
Category
analysis-evasion
Content
Use `scripts/generate-slides.js`:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Use `scripts/generate-slides.js`:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Use `scripts/check-analytics.js` to pull platform analytics and upload history:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Use `scripts/check-analytics.js` to pull platform analytics and upload history:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Hidden Instructions

High
Category
Prompt Injection
Content
</head>
<body>

  <!-- Nav -->
  <nav>
    <div class="container">
      <a href="https://upload-post.com" class="logo">Upload<span>-Post</span></a>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
  </section>

  <!-- Stats -->
  <section>
    <div class="container">
      <div class="stats">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
  </section>

  <!-- Platforms -->
  <section class="platforms">
    <div class="container">
      <h2 class="section-title">One API Call. Every Platform.</h2>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
  </section>

  <!-- All Skills -->
  <section class="skills-section" id="skills">
    <div class="container">
      <h2 class="section-title">Upload-Post Ecosystem</h2>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Exfiltration Commands

High
Category
Prompt Injection
Content
/**
 * Analytics Checker — Upload-Post API
 * 
 * Pulls platform analytics and upload history to track post performance.
 * 
 * How it works:
 * 1. Fetches platform-level analytics (followers, impressions, reach) from Upload-Post
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Exfiltration Commands

High
Category
Prompt Injection
Content
/**
 * Analytics Checker — Upload-Post API
 * 
 * Pulls platform analytics and upload history to track post performance.
 * 
 * How it works:
 * 1. Fetches platform-level analytics (followers, impressions, reach) from Upload-Post
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README promotes automated posting to multiple social platforms, competitor research, analytics collection, and optional conversion tracking, but it does not clearly warn users that content, credentials, analytics, and account actions will be transmitted to third-party services. In an agent-skill context, this omission increases the chance of unintended external actions or data disclosure, especially because the workflow is explicitly designed to automate account-impacting operations.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The README instructs users to run `npx skills add ...` without pinning a specific package version or commit. That can cause users to fetch and execute whatever package version is current at install time, creating a supply-chain risk if the package is updated maliciously, compromised, or changed in an unsafe way.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill describes actions requiring shell and network access but does not declare a restrictive tool scope. That makes the operational boundary ambiguous and can let an agent overreach into installing software, calling external APIs, and performing browser/network actions without explicit least-privilege constraints.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation criteria are broad enough to trigger on common marketing discussions, increasing the chance the skill runs in contexts where users did not intend social posting, analytics collection, or system setup. Overbroad invocation can lead to unnecessary exposure of tools, secrets, and automation flows.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/check-analytics.js:39

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/daily-report.js:43

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/post-to-platforms.js:36