Back to skill

Security audit

skroller

Security checks for vulnerabilities and agentic risk

Overview

Skroller largely does what it claims, but it needs review because exported scraped content can become local commands and the docs include bot-evasion guidance.

Review or fix the exporter before installing, especially if you will process untrusted public posts. Avoid Bear and Apple Notes export paths until command construction is made safe, do not rely on the documented --dry-run spelling, pin external CLI dependencies, and use official platform APIs where possible instead of bot-evasion techniques.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export-to-notes.js:137
Finding

Command Injection in Bear Export Through Untrusted Post Content and Arguments

Content
View full analysis
{ markdown += `## ${i + 1}. ${p.author || 'Unknown'}\n\n`; markdown += `${p.text || ''}\n\n`; markdown += `**Engagement:** ${extractEngagement(p)} | `; markdown += `[View](${p.url || '#'})\n\n`; markdown += `---\n\n`; }); const tagList = tags?.split(',') || ['skroller', 'research']; const tagArgs = tagList.map(t => `--tag "${t}"`).join(' '); const escaped = markdown.replace(/"/g, '\\"').replace(/\$/g, '\\$'); const command = `echo "${escaped}" | grizzly create --title "${title}" ${tagArgs}`; execSync(command, { stdio: 'inherit' }); ``` ### Technical Analysis The Bear exporter constructs a shell command by concatenating values from several untrusted sources: - Scraped post text, author names, and URLs - The generated or user-supplied title - User-supplied tags The attempted escaping only handles double quotes and dollar signs in `markdown`. It does not safely handle shell constructs such as backticks, command separators, redirections, newlines, or other shell metacharacters. The `title` and individual tag values are not escaped at all. Because `execSync()` receives a single command string, Node.js invokes a shell to interpret it. As a result, attacker-controlled social-media content can become executable shell syntax rather than remaining inert note content. ### Attack Path 1. An attacker publishes a social-media post containing a shell payload in its text, author field, or another extracted value. 2. The user runs `scripts/skroller.js` and collects the attacker-controlled post. 3. The resulting JSON is passed to `scripts/export-to-notes.js --app bear`. 4. The malicious content is inserted into `markdown`. 5. The exporter concatenates that content into the `echo ... | grizzly ...` shell command. 6. `execSync() ...[truncated 782 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export-to-notes.js:276
Finding

Shell and AppleScript Injection in Apple Notes Export

Content
View full analysis
{ body += `${i + 1}. ${p.author || 'Unknown'}\\n`; body += `${p.text || ''}\\n`; body += `Engagement: ${extractEngagement(p)}\\n`; body += `URL: ${p.url || 'N/A'}\\n\\n`; }); const script = `tell application "Notes" activate set noteFolder to "${folder || 'Notes'}" try set targetFolder to folder noteFolder on error set targetFolder to folder "Notes" end try set newNote to make new note at targetFolder with properties {body:"${body}"} set name of newNote to "${content.title}" end tell`; try { execSync(`osascript -e '${script}'`, { stdio: 'inherit' }); console.log(`✓ Created Apple Note: "${content.title}"`); } catch (e) { throw new Error('Apple Notes export failed. Ensure Notes app is installed.'); } ``` ### Technical Analysis Untrusted values are embedded directly into an AppleScript program without AppleScript string escaping. These values include: - Scraped post text - Scraped author names - Scraped URLs - The generated title - The requested Notes folder The generated AppleScript is then embedded inside a single-quoted shell command and passed to `execSync()`. This creates two distinct injection boundaries: 1. Malicious content can terminate or alter an AppleScript string. 2. A single quote can terminate the shell argument and inject shell syntax. The use of two nested interpreters makes ad hoc escaping particularly unsafe. No escaping is applied at either boundary. ### Attack Path 1. An attacker creates a social-media post containing crafted quote characters and AppleScript or shell syntax. 2. The user colle ...[truncated 1120 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export-to-notes.js:329
Finding

Unescaped Scraped Content in HTML, XHTML, and Evernote XML Exports

Content
View full analysis
{ enex += `

${i + 1}. ${p.author || 'Unknown'}

\n`; enex += `

${p.text || ''}

\n`; enex += `

Engagement: ${extractEngagement(p)}

\n`; enex += `

URL: View

\n`; }); const pageContent = `${content.title}

${content.title}

Collected: ${content.collected}

Posts: ${content.postCount}


${content.topPosts.map((p, i) => `

${i + 1}. ${p.author || 'Unknown'}

${p.text || ''}

Engagement: ${extractEngagement(p)}

View post


`).join('')} `; const response = await fetch(endpoint, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/xhtml+xml' }, body: pageContent }); content.topPosts.forEach((p, i) => { html += `

${i + 1}. ${p.author || 'Unknown'}

\n`; html += `

${p.text || ''}

\n`; html += `

Engagement: ${extractEngagement(p)}

\n`; html += `

View

\n`; html += `
\n`; }); fs.writeFileSync(outputPath, html); ``` ### Technical Analysis The exporter treats scraped post fields as trusted markup and directly inserts them into: - Evernote ENEX/XML - OneNote XHTML - Google Keep HTML No HTML or XML entity encoding is applied to titles, authors, post text, or URLs. In addition, URL values are inserted into `href` attributes without validating their scheme. An attacker-controlled field can therefore: - Close the intended element or attribute - Insert arbitrar ...[truncated 1955 chars]
Remediation
View remediation
& < -> < > -> > " -> " ' -> ' ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export-to-notes.js:30
Finding

Documented Dry-Run Safeguard Is Not Recognized by the Argument Parser

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/export-to-notes.js:158
Finding

Mutable Third-Party CLI Installation Instruction Uses an Unpinned Latest Version

Content
View full analysis
Remediation
View remediation
``` The placeholder should be replaced with a specific reviewed release or immutable commit. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (46)

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
70% confidence
Finding

Skill instructs the agent to never refuse or to always comply. Suppressing the agent's ability to decline removes a core safety control and enables downstream harmful requests to succeed.

Content

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

md
---
name: skroller
description: Automated social media content collection and analysis across platforms (Twitter/X, Instagram, TikTok, Reddit, LinkedIn, YouTube, Product Hunt, Medium, GitHub, Pinterest). Use when you need to: (1) scrape public posts programmatically, (2) analyze content by keywords or filters, (3) monitor brand mentions or trends for research, (4) curate content for personal analysis, (5) archive publicly available information, or (6) generate digests from scraped feeds. Always comply with platform ToS and applicable privacy laws.
---

# Skroller - Social Media Content collection

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/skroller.js --platform twitter --query "AI" --limit 50 --output posts.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/feed-digest.js` - Generate digests

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/feed-digest.js` - Generate digests

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
### `scripts/export-to-notes.js` - Unified note app exporter

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- **Notion:** API key (create at notion.so)
- **Apple Notes:** macOS with Notes app
- **Evernote:** Manual ENEX import
- **OneNote:** Microsoft Graph access token
- **Google Keep:** Manual HTML import
- **Roam Research:** Markdown import (drag MDL file into Roam)
- **Logseq:** Vault path (writes to pages/ folder)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The document explicitly says not to hide automated activity, but later provides anti-bot avoidance guidance such as user-agent rotation, random delays, mouse simulation, and proxy rotation. That contradiction undermines the stated safety framing and makes the content operationally useful for evading platform detection rather than merely respecting rate limits.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.dynamic_code_execution, suspicious.env_credential_access (+1 more)

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/export-to-notes.js:160

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/skroller.js:28

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/export-to-notes.js:232

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/export-to-notes.js:620