Back to skill

Security audit

Mailchimp To Ghost

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its Mailchimp-to-Ghost purpose, but it needs Review because it uses Ghost admin access and downloads externally supplied image URLs without enough safety controls.

Install only if you are comfortable giving the skill a Ghost Admin API token and allowing it to fetch newsletter-controlled image URLs from the machine running the agent. Run it from the intended skill directory, avoid blindly copying the rm -rf cache/ commands, use reviewed pinned dependencies where possible, and review generated drafts before publishing or using any update/force behavior.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/sync_to_ghost.py:73
Finding

Unrestricted RSS-Controlled Image Downloads Enable Server-Side Request Forgery

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:43
Finding

Unpinned Third-Party Dependency Installation

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The code substantially matches the 'fetch newsletter content from RSS' and 'convert HTML to clean markdown with horizontal rules' parts of the description. However, the declared purpose claims a full sync to Ghost, including image uploads and publishing as Lexical-format posts. This code chunk only performs feed retrieval, HTML cleanup, markdown conversion, and local file output. There is no Ghost authentication, API usage, image upload, or post publishing logic. The special 'button: ...' markers suggest downstream processing may exist elsewhere, but in this chunk the behavior is limited to markdown extraction and caching. Therefore the description overstates what this supplied code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code only implements the Ghost-side import portion of the described workflow. It operates on a local file (cache/newsletter_markdown_1.md) and contains no RSS retrieval, no Mailchimp integration, and no HTML-to-markdown conversion. It does perform image downloading/uploading and Markdown-to-Lexical conversion, including horizontal rules and other formatting. However, the declared description presents a fuller end-to-end sync pipeline and says it publishes posts, while this script creates drafts by default and optionally updates existing posts. These are material differences in primary behavior and capabilities, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
93% confidence
Finding

The skill instructs execution of rm -rf cache/ in a shell pipeline as an 'ALWAYS DO THIS FIRST' step. In an automated agent context, destructive shell parameters are dangerous because path assumptions can fail, aliases/symlinks can redirect deletion, and the command may run in an unintended directory, causing irreversible data loss.

Content

Scanner excerpt · SKILL.md (reported line 70)May include surrounding context.

bash
# 1. Clear any stale cache and fetch fresh from RSS (ALWAYS DO THIS FIRST)
rm -rf cache/ && python3 scripts/fetch_markdown.py

# 2. Sync to Ghost (downloads images, uploads them, creates draft post)
python3 scripts/sync_to_ghost.py

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
92% confidence
Finding

This repeated recommendation to delete cache/ with rm -rf normalizes unsafe shell behavior without path validation. Repetition increases the likelihood that users or agents will execute it blindly, magnifying the risk of accidental deletion if the current directory is not what the instructions assume.

Content

Scanner excerpt · SKILL.md (reported line 89)May include surrounding context.

To force a fresh fetch, delete the cache:

bash
rm -rf cache/

Deduplication

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
92% confidence
Finding

Using rm -rf cache/ in troubleshooting guidance remains dangerous because operators are more likely to copy-paste commands during failure scenarios without verifying context. In support/runbook text for an agent skill, this creates a realistic path to unintended destructive action.

Content

Scanner excerpt · SKILL.md (reported line 209)May include surrounding context.

Fix: Always clear cache and re-fetch before syncing:

bash
rm -rf cache/
python3 scripts/fetch_markdown.py
python3 scripts/sync_to_ghost.py

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
92% confidence
Finding

This instruction again prescribes unguarded recursive deletion for routine maintenance. The skill context makes it more dangerous because the same document also relies on shell execution, file writes, and cached state, so an autonomous tool could plausibly run the command as written with broad filesystem access.

Content

Scanner excerpt · SKILL.md (reported line 218)May include surrounding context.

Delete cache and re-fetch:

bash
rm -rf cache/
python3 scripts/fetch_markdown.py

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill explicitly instructs use of Python scripts, shell commands, network access, and file deletion/writes, yet it declares no tool scope or permission boundaries. In an agent setting, missing scope metadata increases the chance the runtime grants broader capabilities than necessary, making destructive or unintended actions easier if the skill is invoked automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The instructions tell users to place a Ghost admin token in a local env file but provide no warning that this credential grants sensitive administrative access. In a skill ecosystem, omission of credential-handling guidance increases the risk of token leakage through source control, logs, screenshots, or overbroad file access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill recommends rm -rf cache/ as a routine step without emphasizing that it is a destructive command whose safety depends on the current working directory. In agentic or copy-paste workflows, destructive deletion instructions can cause accidental data loss if executed from the wrong path or after path manipulation.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · SKILL.md (reported line 77)May include surrounding context.

text

**Why this matters:** The RSS feed only shows the most recent newsletter(s). If you sync without re-fetching, you may:
- Create duplicate posts (Ghost will add `-2`, `-3` suffixes to slugs)
- Miss new newsletters entirely
- Process outdated content

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script’s documented behavior says it syncs markdown as a draft post, but the implementation can update existing Ghost posts when invoked with --update. This mismatch is dangerous because operators or higher-level agents may grant the skill more trust than warranted, leading to unintended modification of published or draft content in a production CMS.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/sync_to_ghost.py (reported line 28)May include surrounding context.

python
try:
        # Use NQL filter to search for posts with similar title
        # The ~ operator does a partial match
        result = subprocess.run(
            [GHST_BIN, "post", "list", "--filter", f"title:~'{title[:30]}'", "--json"],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/sync_to_ghost.py (reported line 122)May include surrounding context.

python
def upload_image_to_ghost(image_path):
    """Upload an image to Ghost and return the new URL."""
    try:
        result = subprocess.run(
            GHOST_IMAGE_UPLOAD_CMD + [image_path],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/sync_to_ghost.py (reported line 511)May include surrounding context.

python
try:
        cmd.extend(["--lexical-file", lexical_file])
        
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/sync_to_ghost.py (reported line 553)May include surrounding context.

python
try:
        cmd.extend(["--lexical-file", lexical_file])
        
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

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

text
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The inline comment claims an '80% match threshold,' but the code actually returns a match when one normalized title is contained within the other. This is not merely incomplete documentation; it describes a different decision rule than the one implemented.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.