Back to skill

Security audit

TikTok Content Pipeline

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed TikTok/Postiz automation pipeline, but it needs review because it can affect live social accounts and handles the Postiz API key in an unsafe way.

Review this before installing if it will connect to real TikTok/Postiz accounts. Use a least-privilege Postiz key if possible, prefer the environment variable over config files, avoid cron/--post/--auto-improve until you have tested in a throwaway account, and pin/review the Postiz CLI and npm dependencies. Treat logs as sensitive because failures may expose the API key.

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

T09 · Insecure Skill Coding Practices

Error
Location
core/AnalyticsEngine.js:95
Finding

Postiz API Key Exposed Through Shell Command Strings and Error Logs

Content
View full analysis
new Date(post.publishDate) >= cutoffDate ); // Get analytics for each post const postsWithAnalytics = []; for (const post of recentPosts) { try { const analyticsCmd = `POSTIZ_API_KEY=${this._shellEscape(this.postiz.apiKey)} postiz analytics:post ${this._shellEscape(post.id)}`; const analyticsOutput = execSync(analyticsCmd, { encoding: 'utf8' }); ``` ```javascript // core/AnalyticsEngine.js:131 console.error('Failed to fetch post metrics:', error.message); ``` ```javascript // core/AnalyticsEngine.js:143-147 const cmd = `POSTIZ_API_KEY=${this._shellEscape(this.postiz.apiKey)} postiz analytics:platform ${this._shellEscape(integrationId)}`; const output = execSync(cmd, { encoding: 'utf8' }); return JSON.parse(output); } catch (error) { console.error('Failed to fetch platform metrics:', error.message); ``` ```javascript // core/Publisher.js:143-146 const cmd = `POSTIZ_API_KEY=${this._shellEscape(this.postiz.apiKey)} postiz upload ${this._shellEscape(mediaPath)}`; const output = execSync(cmd, { encoding: 'utf8' }); const url = output.trim().split('\n').pop(); mediaUrls.push(url); ``` ```javascript // core/Publisher.js:171-195 _buildPostizCommand(params) { const { integrationId, mediaUrls, caption, title, sc ...[truncated 3066 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
cli.js:76
Finding

Account Creation Allows Path Traversal Within the Project Root

Content
View full analysis
'); return; } const templateDir = path.join(this.templatesDir, template); if (!fs.existsSync(templateDir)) { console.error(`❌ Template '${template}' not found in ${this.templatesDir}`); return; } const accountDir = path.join(this.accountsDir, accountName); if (fs.existsSync(accountDir)) { console.error(`❌ Account '${accountName}' already exists`); return; } ``` ```javascript // cli.js:493-512 _copyDirectory(src, dest) { // Path traversal guard: both src and dest must stay within framework root const resolvedSrc = path.resolve(src); const resolvedDest = path.resolve(dest); const resolvedRoot = path.resolve(this.frameworkRoot); if (!resolvedSrc.startsWith(resolvedRoot) || !resolvedDest.startsWith(resolvedRoot)) { console.error(`❌ Path traversal blocked: copy must stay within framework directory`); process.exit(1); } if (!fs.existsSync(dest)) { fs.mkdirSync(dest, { recursive: true }); } const items = fs.readdirSync(src); for (const item of items) { // Skip dotfiles and suspicious names if (item.startsWith('.') || item.includes('..')) continue; const srcPath = path.join(src, item); const destPath = path.join(dest, item); ``` ### Technical Analysis Other account and template operations apply an alphanumeric, hyphen, and underscore allowlist, but `createAccount` does not validate either `accountName` or `template`. The `_copyDirectory` guard only checks that resolved paths remain under the broad framework root. It does not enforce the intended boundaries that the source must remain und ...[truncated 2031 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
package.json:8
Finding

Unpinned Postiz CLI and Floating Dependency Resolution

Content
View full analysis
- **Postiz account** — [postiz.com](https://postiz.com) (self-hosted or cloud) - **Postiz CLI** — `npm install -g postiz-cli` - **TikTok account** connected to Postiz as an integration - **ImageMagick** (optional, for keyword overlays) — `brew install imagemagick` ## Install ```bash cd /path/to/tiktok-content-pipeline npm install ``` Dependencies: `canvas`, `cheerio`, `sharp` (for image generation). ``` ```json // package.json:8-12 "dependencies": { "canvas": "^3.2.1", "cheerio": "^1.2.0", "sharp": "^0.34.5" } ``` ### Technical Analysis The setup instructions install the latest available `postiz-cli` globally without specifying an audited version. The package dependencies use caret ranges, and the audited project has no lockfile in the provided directory structure. As a result, installation is not reproducible: a future `npm install` can resolve package versions different from those reviewed. This is especially sensitive for `postiz-cli`, because the application passes it the Postiz API key and relies on it for media uploads, analytics access, scheduling, and publication. No evidence was found that the named packages are currently malicious. The confirmed issue is the unsafe dependency-resolution practice and resulting exposure to upstream package compromise or an unexpectedly incompatible release. ### Attack Path 1. A package maintainer account, registry distribution channel, or newly published compatible dependency version is compromised or introduces unsafe code. 2. A user follows the documented installation commands after the affected version becomes available. 3. npm resolves the unpinned global CLI or a newer version permitted by the caret ranges. 4. Package lifecycle scripts or runt ...[truncated 969 chars]
Remediation
View remediation
``` 5. Prefer a project-local development or runtime dependency over a global executable so the lockfile controls its version. 6. Verify package integrity, provenance, maintainers, lifecycle scripts, and release changes before upgrades. 7. Run dependency installation with reduced privileges and avoid installing global npm packages as an administrator. 8. Add automated dependency scanning and a controlled update process that reviews lockfile changes. 9. Consider disabling lifecycle scripts during initial review where compatible: ```bash npm ci --ignore-scripts ``` Native dependencies such as `canvas` and `sharp` may require installation scripts, so any necessary scripts should be explicitly reviewed before enabling them. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (22)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly instructs users to run a command that will generate and publish content to an external service (--post) without clearly warning that this triggers outbound API calls, data transmission, and real publishing actions. In an automation skill that manages multiple accounts and analytics integrations, this omission increases the risk of users unintentionally posting content or exposing account-linked data and credentials through connected services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The setup guide explicitly instructs users to enable automated posting and auto-optimization against connected TikTok/Postiz accounts, but it does not clearly warn that these commands can publish or queue real external content and make account-affecting changes. In a skill that operates social media accounts, this omission increases the chance of unintended posting, reputational damage, or policy/account issues if a user runs commands without understanding their effects.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring says the engine 'Pulls data from Postiz, analyzes performance, and auto-implements improvements,' implying that automatic changes are part of normal behavior. In the code, implementation only occurs conditionally when autoImplement is explicitly enabled in generateReport; otherwise the engine only analyzes data and writes reports.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

When autoImplement is enabled, the engine can modify account files by executing optimization actions without any confirmation, dry-run, or per-action approval at the decision point. In an agent skill context, this increases the chance of unintended state changes or destructive edits if analytics data, recommendations, or downstream action handlers are wrong or manipulated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code places the Postiz API key directly into a shell command environment assignment and invokes execSync, which exposes sensitive credentials to subprocess execution and potentially to process listings, logs, crash reports, or shell-level side effects. Although shell escaping reduces command injection risk, using a shell at all for secret-bearing operations is unnecessarily dangerous in a skill that handles external integrations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The post() flow builds and executes a Postiz command that publishes content and captions to a third-party platform, which can affect user data and external accounts. Although it logs that publishing is occurring, the file does not provide a clear warning, confirmation, or descriptive disclosure that this action posts externally and may be irreversible.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code uploads user-provided media files to Postiz, which is a network operation that transmits user data externally. While there is a console log for each file upload, it only reports progress and does not disclose the privacy-impacting behavior in a user-warning comment, prompt, or broader skill description visible in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The date and time helpers hard-code en-GB in toLocaleDateString and toLocaleTimeString, which forces a specific language/locale for all users. This is a natural-language policy concern because the file provides no opt-in, configuration, or documented region-specific justification for the locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The value "Europe/London" sets a fixed locale-specific posting timezone in natural-language configuration. Under the policy rule, forcing a specific locale without opt-in or documented justification can be a language/locale policy issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The engine creates directories and writes both JSON and Markdown report files under the account directory. While the method comment notes that a report is saved, there is no clear user-facing warning at runtime or in this file about persistent local writes that may store potentially sensitive analytics data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The timezone helper hard-codes en-US in toLocaleString, which imposes a specific language/locale choice in behavior visible through date parsing and formatting logic. The file does not offer a locale option or explain why a U.S. English locale is required, which conflicts with the policy against forcing a locale without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The module docstring says it handles posting to TikTok "and other platforms" and provides a "unified interface," but the public method documentation at L25 and default behavior at L34 are specifically TikTok-oriented, with no visible generic platform abstraction beyond selecting an integration ID. This is a documentation-level overstatement of breadth rather than a direct security issue, but it is an intent/documentation mismatch.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The scheduleBatch docstring says it uses scheduling preferences, and the code accepts a timezone option at L101, implying it affects scheduling semantics. However, timezone is never used in calculating currentTime or posting times, so the documented intent of timezone-aware scheduling is contradicted by the implementation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code saves publishing metadata, including post information and results, into a local .metadata directory. This file write is documented as analytics-related in a comment, but there is no explicit user disclosure that local storage will occur or what data will be retained.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code explicitly uses toLocaleDateString('en-US', ...), which forces a specific locale regardless of user or deployment preferences. The policy allows locale constraints only when users are offered a choice or when the restriction is clearly justified, neither of which is present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This line again forces en-US when deriving the weekday name for scheduling logic. Requiring a specific language/locale in behavior without opt-in or clear justification is a natural-language policy concern under the locale policy rule.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency uses a caret range (^3.2.1), so builds may resolve to newer transitive code over time rather than a strictly reviewed version. This weakens reproducibility and can unintentionally introduce vulnerable or malicious upstream releases into the supply chain.

Content

Scanner excerpt · package.json (reported line 10)May include surrounding context.

json
"content-pipeline": "./cli.js"
  },
  "dependencies": {
    "canvas": "^3.2.1",
    "cheerio": "^1.2.0",
    "sharp": "^0.34.5"
  },

Unverifiable Dependency: canvas has 2 known advisory(ies) (CVE-2020-8215 (Buffer overflow in canvas); GHSA-vpq5-4rc8-c222 (Denial of Service in canvas)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The cheerio dependency is not pinned to an exact version, allowing future installs to pull different code than originally audited. While not an exploit by itself, this creates supply-chain risk and makes it harder to verify whether deployed versions are affected by security issues.

Content

Scanner excerpt · package.json (reported line 11)May include surrounding context.

json
},
  "dependencies": {
    "canvas": "^3.2.1",
    "cheerio": "^1.2.0",
    "sharp": "^0.34.5"
  },
  "keywords": ["tiktok", "content-pipeline", "carousel", "postiz", "automation", "openclaw-skill"],

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The sharp dependency is specified with a version range instead of an exact version, which can result in different resolved packages across environments. Because sharp includes native components and a complex dependency chain, unpinned resolution increases supply-chain and patch-verification risk.

Content

Scanner excerpt · package.json (reported line 12)May include surrounding context.

json
"dependencies": {
    "canvas": "^3.2.1",
    "cheerio": "^1.2.0",
    "sharp": "^0.34.5"
  },
  "keywords": ["tiktok", "content-pipeline", "carousel", "postiz", "automation", "openclaw-skill"],
  "license": "MIT"

Unverifiable Dependency: sharp has 4 known advisory(ies) (GHSA-54xq-cgqr-rpm3 (sharp vulnerability in libwebp dependency CVE-2023-4863); GHSA-f88m-g3jw-g9cj (sharp inherited vulnerabilities in libvips: CVE-2026-33327, CVE-2026-33328, CVE-); CVE-2022-29256 (sharp vulnerable to Command Injection in post-installation over build environmen) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This JSON manifest describes the file as a generic 'starter template' to adapt for a niche, but it does not define any specific invocation scope, trigger phrases, or exclusion conditions. For manifest files, such broad natural-language descriptions can contribute to ambiguous activation behavior if used by a skill discovery or routing system.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
core/AnalyticsEngine.js:96

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
core/Publisher.js:70