Back to skill

Security audit

Neckr0ik Newsletter Manager

Security checks for vulnerabilities and agentic risk

Overview

This skill is not backed by evidence of malware, but it overstates real newsletter delivery and analytics while handling credentials and subscriber data with weak safeguards.

Install only for local drafting experiments, not production newsletter operations. Do not enter live API keys or import real subscriber lists unless the storage, redaction, and permissions issues are fixed. Treat send, schedule, web curation, and analytics output as simulated until real provider integrations and explicit approval safeguards are implemented.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/newsletter.py:254
Finding

Arbitrary JSON File Modification Through Unsanitized Draft Identifier

Content
View full analysis
bool: """Schedule newsletter for delivery.""" draft_file = self.drafts_dir / f"{draft_id}.json" if not draft_file.exists(): print(f"✗ Draft not found: {draft_id}") return False # Load draft newsletter_data = json.loads(draft_file.read_text()) # Parse send time if optimal: # Calculate optimal send time (9 AM in recipient timezone) send_dt = datetime.now().replace(hour=9, minute=0, second=0, microsecond=0) if send_dt < datetime.now(): send_dt += timedelta(days=1) else: send_dt = datetime.fromisoformat(send_time.replace('Z', '+00:00')) # Update draft newsletter_data['scheduled_at'] = send_dt.timestamp() newsletter_data['status'] = 'scheduled' draft_file.write_text(json.dumps(newsletter_data, indent=2)) ``` The same flaw is present in the sending operation: ```python def send(self, draft_id: str, test_email: Optional[str] = None, segment: Optional[str] = None, platform: Optional[str] = None) -> bool: """Send newsletter.""" draft_file = self.drafts_dir / f"{draft_id}.json" if not draft_file.exists(): print(f"✗ Draft not found: {draft_id}") return False newsletter_data = json.loads(draft_file.read_text()) platform = platform or newsletter_data.get('platform', 'substack') print(f"✓ Sending: {draft_id}") print(f" Platform: {platform}") if test_email: print(f" Test mode: sending to {test_email}") # In real implementation, would send test email else: print(f" Recipients: All subscribers") # In real ...[truncated 2245 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/newsletter.py:103
Finding

Plaintext Storage and Terminal Disclosure of API Secrets and Subscriber PII

Content
View full analysis
dict: """Load configuration.""" if self.config_file.exists(): return json.loads(self.config_file.read_text()) return {"platform": "substack", "default_style": "professional"} def _save_config(self, config: dict): """Save configuration.""" self.config_file.write_text(json.dumps(config, indent=2)) ``` Imported subscriber names and email addresses are also stored as plaintext JSON: ```python subscriber = Subscriber( email=email.strip(), name=name.strip() if name else None, ) # Save subscriber sub_file = self.subscribers_dir / f"{hashlib.md5(email.encode()).hexdigest()[:12]}.json" sub_file.write_text(json.dumps(subscriber.__dict__, indent=2)) count += 1 ``` Configuration values, including documented API secrets, are echoed to the terminal: ```python if args.action == 'set': keys = args.key.split('.') current = config for key in keys[:-1]: if key not in current: current[key] = {} current = current[key] current[keys[-1]] = args.value manager._save_config(config) print(f"✓ Set {args.key} = {args.value}") ``` The documentation specifically directs users to configure sensitive provider credentials: ```bash neckr0ik-newsletter-manager config set beehiiv.api_key neckr0ik-newsletter-manager config set convertkit.api_key neckr0ik-newsletter-manager config set convertkit.api_secret ``` ### Technical Analysis The application treats all configuration values identically, despite some documented keys being API keys or API secrets. These values are persisted in `config.json` without e ...[truncated 2246 chars]
Remediation
View remediation

other

Warning
Location
scripts/newsletter.py:287
Finding

Newsletter Delivery and Analytics Falsely Report Success Without Provider Operations

Content
View full analysis
bool: """Send newsletter.""" draft_file = self.drafts_dir / f"{draft_id}.json" if not draft_file.exists(): print(f"✗ Draft not found: {draft_id}") return False newsletter_data = json.loads(draft_file.read_text()) platform = platform or newsletter_data.get('platform', 'substack') print(f"✓ Sending: {draft_id}") print(f" Platform: {platform}") if test_email: print(f" Test mode: sending to {test_email}") # In real implementation, would send test email else: print(f" Recipients: All subscribers") # In real implementation, would send to platform API # Mark as sent newsletter_data['sent_at'] = time.time() newsletter_data['status'] = 'sent' draft_file.write_text(json.dumps(newsletter_data, indent=2)) print(f"✓ Sent successfully") return True ``` Analytics are generated from fixed percentages instead of provider observations: ```python def get_analytics(self, period: int = 30, newsletter_id: Optional[str] = None) -> dict: """Get newsletter analytics.""" # In real implementation, would query platform APIs # For now, return simulated analytics analytics = { "period_days": period, "total_sent": 0, "total_opens": 0, "total_clicks": 0, "open_rate": 0.0, "click_rate": 0.0, "subscribers": 0, "growth": 0.0, } # Count subscribers for _ in self.subscribers_dir.g ...[truncated 2793 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented behavior overstates real integration and sending capabilities, creating a description-behavior mismatch. This is dangerous because users may trust the skill to perform real newsletter delivery or platform operations, causing unsafe operational assumptions, accidental disclosure of subscriber data to unsupported paths, or secret entry into a tool that cannot securely use them.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scripts/newsletter.py (reported line 408)May include surrounding context.

python
s:
                    continue
                drafts.append(data)
            except json.JSONDecodeError:
                continue
        
        # Sort by creation time, newest first
        drafts.sort(key=lambda x: x.get('created_at', 0), reverse=True)
        
        return drafts


def main():
    """CLI entry point."""
    
    import argparse
    
    parser = argparse.ArgumentParser(description="Newsletter Manager")
    subparsers = parser.add_subparsers(dest='command', help='Command')
    
    # create command
    create_parser = subparsers.add_parser('create', help='Create newsletter draft')
    create_parser.add_argument('--topic', required=True, help='Newsletter topic')
    create_parser.add_argument('--style', default='professional', 
                                choices=['professional', 'casual', 'technical', 'newsy'])
    create_parser.add_argument('--length', type=int, default=500)
    create_parser.add_argument('--curate', action='store_true', help='Curate lin

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises operational capabilities such as file access, writing, and shell-like execution patterns, but it does not declare any explicit tool scope or permissions boundary. In an agent ecosystem, this weakens reviewability and can lead to over-privileged execution, making it easier for the skill to access local files or perform unintended actions without informed user consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly promotes sending to all subscribers with no caution about bulk outbound impact, consent, rate limits, or accidental mass delivery. In a newsletter-management context, this increases the risk of spam, reputational damage, compliance violations, and unintended large-scale actions triggered by an agent or user mistake.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Importing and exporting subscriber lists inherently involves personal data, yet the skill provides no warning about privacy, secure storage, minimization, or lawful handling. In this context, that omission is risky because newsletter subscriber data commonly includes email addresses and segmentation metadata that could be exposed, mishandled, or exported insecurely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup instructions ask users to enter API keys and secrets without any warning that these credentials are highly sensitive. This is particularly dangerous in an AI-agent skill because users may provide live production credentials into insecure contexts, leading to account takeover, unauthorized newsletter sends, subscriber data access, or abuse of connected platforms.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill advertises support for multiple newsletter platforms, but the platform definitions are only static metadata and are not backed by implemented API behavior. In an agent context, this mismatch can cause unsafe reliance on nonexistent integrations, leading to silent failures or incorrect automation decisions.

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/newsletter.py (reported line 174)May include surrounding context.

python
try:
            # Call ollama
            result = subprocess.run(
                ["ollama", "run", "llama3.2:latest", prompt],
                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/newsletter.py (reported line 227)May include surrounding context.

python
try:
            # Search for recent content on topic
            result = subprocess.run(
                ["ollama", "run", "llama3.2:latest", 
                 f"List 5 recent and important news items about {topic}. Format as JSON array with title and url fields."],
                capture_output=True,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The send method claims successful delivery and marks drafts as sent even though it does not contact any newsletter platform API. This can mislead operators into believing communications were delivered, causing business/process integrity failures and potentially unsafe downstream automation based on false send state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The import routine writes subscriber email addresses and names to disk as plaintext JSON files without warning, consent handling, retention controls, or access protections. In a newsletter-management skill, this materially increases privacy and compliance risk because it stores personal data in a predictable local directory.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The description advertises broad autonomous newsletter management capabilities without clear trigger boundaries, approval requirements, or platform-specific safety constraints. In an agent ecosystem, this can cause over-activation or misuse for mass content generation and sending, especially because the skill implies end-to-end automation across multiple email platforms.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The _curate_links docstring says it curates relevant links from web search, which implies retrieving current web results. The implementation instead invokes ollama run with a prompt asking for recent items and then extracts lines containing 'http', without performing any actual web search.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The method name and docstring present this as getting newsletter analytics, which suggests real measured campaign data. The implementation only counts local subscriber files and fabricates open, click, and growth metrics using fixed percentages.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.