Back to skill

Security audit

LarrySkill

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a disclosed TikTok marketing automation workflow, but it asks for persistent API-driven social and revenue analytics access while storing sensitive keys and transaction data too loosely.

Review before installing. Use a separate working directory, do not commit tiktok-marketing/config.json or analytics snapshots, prefer environment variables or a secret manager for all API keys, and rotate any key that was stored in a shared file. Approve any browser research, npm install, sudo command, RevenueCat skill installation, Postiz posting, cross-posting, and daily scheduled job explicitly. If enabling RevenueCat, store only aggregate metrics or de-identified timestamps and set a retention/deletion policy for local reports and snapshots. Use a neutral Postiz signup URL if you do not want to use the author referral link.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:217
Finding
Hardcoded Affiliate Referral Steers Agent Onboarding Output<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:217-223` **Vulnerability Type**: Commercial output steering through Skill instructions **Risk Level**: High ### Vulnerable Code ```markdown > "So here's the key piece — we need Postiz to handle posting and analytics. It's what lets me track every post's performance and tell you exactly which hooks are driving views and which to drop. Without it, we're guessing. With it, I can run a daily report that shows you what's working and automatically suggest better hooks." > > "This skill is free and open source. If you want to support its development, signing up through this link is appreciated: [postiz.pro/oliverhenry](https://postiz.pro/oliverhenry)" Walk them through connecting step by step: 1. **Sign up at [postiz.pro/oliverhenry](https://postiz.pro/oliverhenry)** — create an account ``` The same referral is also presented as a prerequisite at `SKILL.md:19`. ### Technical Analysis The Skill explicitly instructs the agent to incorporate an author-controlled referral URL into the onboarding conversation and to “frame it naturally.” The referral is not technically necessary for Postiz integration: the agent could direct the user to a neutral official service URL and still complete the declared posting and analytics workflow. This alters the agent’s otherwise neutral recommendation behavior for the commercial benefit of the Skill author. Although the text briefly says that use of the link supports development, it does not clearly identify the link as an affiliate or referral relationship, explain whether compensation is received, or give the user a neutral alternative. The behavior therefore constitutes instruction-level output steering rather than an implementation requirement. ### Attack Path 1. A user loads the Skill to configure TikTok marketing automation. 2. The agent follows the mandatory Postiz onboarding instructions in `SKILL.md`. 3. The agent presents the embedded `postiz.pro/oliverh ...[truncated 690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the referral URL with Postiz’s neutral official URL. 2. Do not require the agent to promote an author-controlled link as part of onboarding. 3. If a referral link is retained: - Explicitly label it as an affiliate or referral link. - Explain whether the Skill author may receive compensation or credit. - Present the neutral official URL with equal prominence. - Require the user to choose explicitly before opening or using the referral. 4. Remove wording that directs the agent to conceal or soften the commercial nature of the recommendation by framing it “naturally.” 5. Separate optional project-support messaging from technical prerequisites. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/onboarding.js:43
Finding
Privileged API Credentials Are Stored in Plaintext Configuration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/onboarding.js:43-74` **Additional Locations**: `SKILL.md:339-369`, `references/revenuecat-integration.md:5-16` **Vulnerability Type**: Plaintext credential storage **Risk Level**: High ### Vulnerable Code ```javascript const configTemplate = { app: { name: '', description: '', audience: '', problem: '', differentiator: '', appStoreUrl: '', category: '', isMobileApp: false }, imageGen: { provider: '', apiKey: '', model: '' }, postiz: { apiKey: '', integrationIds: { tiktok: '' } }, revenuecat: { enabled: false, v2SecretKey: '', projectId: '' }, posting: { privacyLevel: 'SELF_ONLY', schedule: ['07:30', '16:30', '21:00'], crossPost: [] }, competitors: `${dir}/competitor-research.json`, strategy: `${dir}/strategy.json` }; const cfgPath = `${dir}/config.json`; if (!fs.existsSync(cfgPath)) { fs.writeFileSync(cfgPath, JSON.stringify(configTemplate, null, 2)); console.log(`📝 Created ${cfgPath}`); } ``` The Skill documentation instructs users to populate these fields directly: ```json { "imageGen": { "provider": "openai", "apiKey": "sk-...", "model": "gpt-image-1.5" }, "postiz": { "apiKey": "your-postiz-key" }, "revenuecat": { "enabled": false, "v2SecretKey": "sk_...", "projectId": "proj..." } } ``` ### Technical Analysis The generated `config.json` is designed to contain OpenAI, Stability AI, or Replicate credentials, a Postiz API key, and a privileged RevenueCat secret key. The file is written using default filesystem permissions and without encryption, an operating-system secret store, environment-variable indirection, or an explicit restrictive mode such as `0600`. The project also does not create or verify a `.gitignore` rule for the generated marketing directory. Consequently, credentials may be included in source-control commits, backups, ...[truncated 1696 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove secret values from `config.json`. Store only environment-variable names or secret references, for example: ```json { "imageGen": { "apiKeyEnv": "OPENAI_API_KEY" }, "postiz": { "apiKeyEnv": "POSTIZ_API_KEY" }, "revenuecat": { "apiKeyEnv": "RC_API_KEY" } } ``` 2. Update every script to resolve credentials from `process.env` or an operating-system secret manager. 3. If a local secret file must be supported: - Create it with mode `0600`. - Keep it separate from non-secret configuration. - Refuse to run if permissions permit group or world access. 4. Automatically add generated secret files and the relevant local workspace to `.gitignore`. 5. Add validation that detects credentials committed to configuration and warns the user without printing the secret. 6. Request provider keys with the narrowest available scopes and separate read-only analytics keys from posting or administrative keys. 7. Document rotation and revocation procedures. 8. Make the RevenueCat instructions consistent with the executable implementation by using `RC_API_KEY` throughout. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/daily-report.js:67
Finding
Complete RevenueCat Transaction Responses Are Persisted Without Data Minimization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/daily-report.js:67-80` and `scripts/daily-report.js:194-200` **Vulnerability Type**: Excessive local retention of sensitive transaction data **Risk Level**: Medium ### Vulnerable Code ```javascript // Get overview metrics const overviewRes = await fetch(`${RC_URL}/projects/${config.revenuecat.projectId}/metrics/overview`, { headers }); const overview = await overviewRes.json(); // Get recent transactions for conversion attribution const txRes = await fetch(`${RC_URL}/projects/${config.revenuecat.projectId}/transactions?start_from=${startDate.toISOString()}&limit=100`, { headers }); const transactions = await txRes.json(); // Extract key metrics from overview array const metricsMap = {}; if (overview.metrics) { overview.metrics.forEach(m => { metricsMap[m.id] = m.value; }); } return { overview, transactions: transactions.items || [], mrr: metricsMap.mrr || 0, activeTrials: metricsMap.active_trials || 0, activeSubscribers: metricsMap.active_subscriptions || 0, activeUsers: metricsMap.active_users || 0, newCustomers: metricsMap.new_customers || 0, revenue: metricsMap.revenue || 0 }; ``` The returned object is then saved wholesale: ```javascript const rcSnapshotPath = path.join(baseDir, 'rc-snapshot.json'); if (fs.existsSync(rcSnapshotPath)) { rcPrevMetrics = JSON.parse(fs.readFileSync(rcSnapshotPath, 'utf-8')); } if (rcMetrics) { fs.writeFileSync(rcSnapshotPath, JSON.stringify({ date: dateStr, ...rcMetrics }, null, 2)); } ``` ### Technical Analysis The report fetches up to 100 transaction objects from RevenueCat and keeps the complete API response in `rcMetrics.transactions`. It also keeps the complete overview response. The entire object is serialized to `rc-snapshot.json`. However, the attribution implementation only needs aggregate metric values and transaction timestamps: ```javascript const txDate = new Date(tx.purchase_date || tx.created_at); ``` Persisting ...[truncated 1799 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not persist the raw `overview` or transaction API responses. 2. Transform transactions in memory into the minimum required representation, for example: ```javascript const attributionEvents = (transactions.items || []).map(tx => ({ timestamp: tx.purchase_date || tx.created_at })); ``` 3. Prefer daily aggregate conversion counts where individual transaction records are unnecessary. 4. Remove customer identifiers, product identifiers, store metadata, and other unused fields before any disk write. 5. Write snapshots with mode `0600` and place them in a user-private data directory. 6. Define and enforce a short retention period; delete snapshots once the required comparison window expires. 7. Add a user-facing consent step that explains transaction-level processing and retention. 8. Ensure reports contain only aggregated values where possible. 9. Document the data flow and provide a command that securely deletes stored analytics snapshots. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:248
Finding
Third-Party Dependencies and Skills Are Installed Without Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:248-252` and `SKILL.md:438-458` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code The Skill directs installation of another Skill without pinning or source verification: ```markdown 1. **Install the RevenueCat skill from ClaWHub:** ``` clawhub install revenuecat ``` This installs the `revenuecat` skill (v1.0.2+) which gives full API access to your RevenueCat project — metrics overview, customers, subscriptions, offerings, entitlements, transactions, and more. ``` It also installs the latest resolved native Node.js dependency: ```bash npm install canvas ``` For Ubuntu and Debian systems, the setup flow additionally instructs: ```bash sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev npm install canvas ``` ### Technical Analysis The commands resolve mutable package or Skill versions at installation time. The project includes no `package.json`, lockfile, integrity hash, reviewed tarball checksum, exact package version, or publisher verification procedure. This is especially significant for `canvas`, which is a native module and may execute installation scripts or load native/prebuilt binaries. The separately installed RevenueCat Skill is described as having broad access to projects, customers, subscriptions, offerings, entitlements, and transactions. Installing an unreviewed future version while RevenueCat credentials are available creates a high-value supply-chain boundary. The audit found no evidence that the current `canvas` package or RevenueCat Skill is malicious. The vulnerability is that the instructions do not ensure that the code installed in the future is the same code that was reviewed. ### Attack Path 1. The user or agent follows the setup instructions. 2. `npm` or ClaWHub resolves the current mutable release rather than an exact audited version. 3. A ...[truncated 1065 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a `package.json` and lockfile that pin an exact reviewed `canvas` version. 2. Use reproducible installation commands such as `npm ci` rather than resolving the latest package dynamically. 3. Preserve and verify package integrity hashes. 4. Pin the RevenueCat Skill to an exact reviewed version if the registry supports version-qualified installation. 5. Document the expected publisher, repository, release checksum, and review date for every external component. 6. Require explicit user confirmation before: - Installing native packages. - Running package lifecycle scripts. - Installing another Skill. - Executing commands with `sudo`. 7. Review the permissions and source code of the RevenueCat Skill separately before granting it a secret key. 8. Use a narrowly scoped, read-only RevenueCat key where supported. 9. Run native image-processing dependencies in a constrained environment with limited filesystem and network access. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (44)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The code chunk implements only one narrow subtask: adding text overlays to six slideshow images. It processes local files, wraps text, positions it on images, and saves PNG outputs. It does not perform browser research, generate images, call any social/posting APIs, track analytics or conversions, or run any optimization/iteration loop. While text overlays are mentioned in the description, the declared purpose presents a broad end-to-end TikTok marketing automation system, which this code does not substantiate. Therefore the description materially overstates the actual behavior of this supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The description presents a broad end-to-end TikTok marketing automation system, but the supplied code only handles a narrow analytics maintenance/reporting function. Specifically, it queries Postiz for TikTok posts, connects missing TikTok video IDs to those posts, retrieves engagement analytics, outputs summaries, and writes a local snapshot file. It does not perform competitor research, generate images, add overlays, create slideshows, publish posts, cross-post to other platforms, track conversions, or iterate content strategy. While analytics tracking is one declared sub-capability, the code chunk's actual primary purpose is much narrower than the declared skill description, so the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description promises an end-to-end TikTok marketing automation system with content generation, posting, cross-platform distribution, analytics, and feedback-loop optimization. The supplied code chunk does not implement those capabilities. Instead, it is a narrow file-management script for competitor research data: loading/saving JSON, adding a competitor entry, and printing summaries/gap analysis. While this fits a small supporting part of the declared competitor-research feature, the actual code's purpose is materially narrower than the declared purpose and lacks most of the advertised functionality. Therefore this is a description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description describes a broad end-to-end TikTok marketing automation workflow. The supplied code chunk has a much narrower purpose: generating six raw image slides from prompts and saving them locally. While AI image generation is one subset of the declared functionality, the code does not implement the majority of the advertised capabilities, including research, posting, analytics, optimization, or conversion tracking. Therefore the description does not accurately represent what this specific code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents a comprehensive TikTok marketing automation system. The supplied code chunk only handles onboarding setup: creating folders/files and validating configuration completeness. While the config schema references concepts like Postiz, competitors, strategy, cross-posting, and RevenueCat, the script merely scaffolds and checks those settings; it does not execute the marketing workflow itself. This is a materially different and much narrower behavior than the declared primary purpose, so it is a clear mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents a broad end-to-end TikTok marketing automation system with research, content generation, analytics, experimentation, and feedback-loop optimization. The supplied code only performs a narrow posting function: it reads six existing PNG files from a directory, uploads them to Postiz, creates a TikTok slideshow post with configurable privacy/title/caption, and writes a local meta.json file. This is a materially different and much smaller scope than declared. There are no undeclared dangerous capabilities apparent, but the description substantially overstates what this code chunk actually does.

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
97% confidence
Finding
The skill normalizes placing sensitive secrets such as OpenAI, Postiz, and RevenueCat API keys directly into a local JSON config file, without strong warnings about plaintext storage or leakage. If that file is committed, synced, logged, or read by other tools, attackers could hijack posting accounts, analytics, billing-linked services, and revenue data.

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 automate the connection:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
Use `scripts/check-analytics.js` to automate the connection:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill clearly expects network-capable actions such as browsing TikTok/App Store, calling Postiz and OpenAI APIs, and pulling RevenueCat data, yet it declares no explicit tool scope or permissions. That creates an overbroad trust boundary where an agent may use whatever network tools are available, making review, sandboxing, and consent enforcement weaker.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The invocation description is broad enough to trigger on generic social media, growth, or app marketing conversations. Over-broad activation can cause the agent to initiate browser research, API setup, or credential collection in contexts where the user did not specifically request this skill.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The skill instructs the agent to research and install Node.js and native packages on the host, including build-tool dependencies. Host-level package installation expands the blast radius from a content-marketing workflow into system modification, increasing risk of supply-chain compromise, environment breakage, or unauthorized changes.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The skill instructs installation of another skill via an external package manager, effectively chaining trust to a second package with its own permissions and code. That expands the local attack surface and creates a supply-chain risk not strictly necessary for the base skill's operation.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill directs creation of a persistent daily cron job on the host. Persistence broadens impact well beyond a one-time marketing task: if misconfigured or later modified, it can repeatedly access APIs, process data, or exfiltrate information without renewed user intent.

Ssd 3

Medium
Confidence
92% confidence
Finding
The workflow persistently stores and tracks multiple high-value API credentials as part of normal operation. Persistent local secret storage increases exposure through backups, shell history, process listings, accidental sharing, and compromise of the developer workstation.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
>
> **Ubuntu/Debian:**
> ```bash
> sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
> npm install canvas
> ```
>
Confidence
88% confidence
Finding
The skill includes `sudo apt-get install ...` guidance for system-wide package installation. Even as documentation, recommending privileged host changes for a marketing workflow raises the chance that an agent or user executes broad root-level modifications, which can harm system integrity or introduce compromised packages.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The file instructs storing post-performance data and optionally correlating it with RevenueCat conversion events, but it does not include any explicit privacy notice, consent requirement, retention limit, or guidance on handling potentially sensitive analytics data. In a marketing automation skill, tying content performance to downstream conversions can create behavioral profiling and compliance risk if users implement it without understanding privacy implications.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The file explicitly instructs users to place a RevenueCat secret API key (sk_) into config.json, but provides no warning about secret management or exposure risks. Configuration files are commonly committed to source control or copied across environments, and compromise of this key would allow unauthorized access to subscriber and revenue data via the RevenueCat API.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation recommends storing RevenueCat webhook event data in a local JSON file without any guidance on access controls, retention, minimization, or exclusion of customer identifiers. Even if the example shows limited fields, real webhook payloads commonly include customer and subscription metadata, so this pattern can lead to inadvertent collection and insecure storage of sensitive business and user data.

External Transmission

Medium
Category
Data Exfiltration
Content
return null;
  }
  
  const RC_URL = 'https://api.revenuecat.com/v2';
  const headers = {
    'Authorization': `Bearer ${config.revenuecat.v2SecretKey}`,
    'Content-Type': 'application/json'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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:47