Back to skill

Security audit

Clawbsky

Security checks for vulnerabilities and agentic risk

Overview

This is a real Bluesky automation CLI, but it has high-impact account actions and credential/session handling that need careful review before installation.

Install only if you are comfortable granting a local CLI durable access to your Bluesky account and using it for live posting, following, unfollowing, blocking, muting, reposting, scheduling, RSS fetching, webhook delivery, and LLM-assisted content processing. Use a dedicated app password or test account, inspect stored sessions under .config, avoid running bulk cleanup/follow scripts without manual review, and do not configure RSS feeds, webhooks, or LLM endpoints you do not trust.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/auth.ts:156
Finding

Arbitrary JSON File Deletion Through Profile Logout Path Traversal

Content
View full analysis
{ const targetHandle = handle || getHandleFromArgs() || getActiveHandle(); if (targetHandle) { const userSessionFile = path.join(sessionsDir, `${targetHandle}.json`); if (fs.existsSync(userSessionFile)) { fs.unlinkSync(userSessionFile); console.log(`✅ Logged out @${targetHandle}`); } ``` ### Technical Analysis The profile handle can originate from the `auth logout` argument or the global `--user` argument. It is interpolated directly into a filesystem path without validating that it is a legitimate Bluesky handle. `path.join()` normalizes traversal components such as `../`. Consequently, a crafted handle can cause `userSessionFile` to resolve outside `sessionsDir`. The forced `.json` suffix restricts the vulnerable operation to filenames ending in `.json`, but it does not guarantee that the target remains inside the intended session directory. No canonical-path containment check is performed before `fs.unlinkSync()` deletes the resolved file. ### Attack Path 1. Identify a JSON file writable by the account running Clawbsky. 2. Calculate a traversal path from `.config/sessions` to the target, omitting the target's `.json` suffix. 3. Invoke a command such as: ```bash clawbsky auth logout "../../../../path/to/target" ``` 4. The application appends `.json`, normalizes the path, checks whether the target exists, and deletes it. 5. No confirmation or containment validation prevents the deletion. ### Impact Assessment An attacker who can control Clawbsky command arguments can delete arbitrary accessible JSON files under the privileges of the Clawbsky process. Potential targets include application configuration, authentication material, persistent Agent state, ...[truncated 226 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/integrations/index.ts:208
Finding

Unrestricted RSS URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
{ try { const response = await fetch(url); const text = await response.text(); ``` ```ts for (const feed of feeds) { try { const items = await fetchRssFeed(feed.url); for (const item of items) { // Skip if already posted if (item.link === feed.lastPostUri) continue; // Queue for posting (actual posting happens elsewhere) const stmt = db.prepare(` INSERT INTO rss_posts (feedId, title, link, content) VALUES (?, ?, ?, ?) `); ``` ### Technical Analysis RSS URLs are stored and later passed directly to `fetch()` without restrictions on: - URL scheme - Destination hostname - Resolved IP address - Redirect destinations - Loopback, private, link-local, or cloud metadata networks - Request timeout - Maximum response size A caller can therefore direct the Skill to issue requests from the environment in which it runs. This may expose network services that are inaccessible from the attacker's own machine. Redirects can also be used to bypass validation if validation is added only to the initial URL. Calling `response.text()` without a size limit can additionally consume excessive memory when a remote endpoint returns a very large or non-terminating response. ### Attack Path 1. Add an RSS feed who ...[truncated 1318 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/integrations/index.ts:120
Finding

Webhook Delivery Sends Event Data and Secrets to Unrestricted Destinations

Content
View full analysis
): Promise<{ sent: number; failed: number }> { const webhooks = getWebhooks().filter(w => w.enabled && w.events.includes(event) ); let sent = 0; let failed = 0; for (const webhook of webhooks) { try { const payload = { event, timestamp: new Date().toISOString(), data }; // Simple fetch (in real implementation, use proper signing) const response = await fetch(webhook.url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(webhook.secret ? { 'X-Webhook-Secret': webhook.secret } : {}) }, body: JSON.stringify(payload) }); if (response.ok) { sent++; } else { failed++; } } catch (error) { failed++; } } ``` ### Technical Analysis Webhook destinations are accepted without scheme, hostname, resolved-address, or redirect validation. When an event is triggered, caller-supplied event data is serialized and sent to the stored destination. If a webhook secret is configured, the secret itself is transmitted in the `X-Webhook-Secret` header. Because HTTP destinations are not rejected, the secret and event payload can travel in plaintext and be intercepted or modified in tra ...[truncated 1625 chars]
Remediation
View remediation
`. 6. Add request timeouts, payload-size limits, retry limits, and destination-specific rate limits. 7. Encrypt stored webhook secrets or keep them in an operating-system secret store. 8. Ensure webhook creation and triggering are restricted to explicitly authorized local users or administrative interfaces. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.ts:64
Finding

Reusable Bluesky Session Tokens Are Persisted in Plaintext Without Explicit Restrictive Permissions

Content
View full analysis
0) { fs.writeFileSync(activeFile, JSON.stringify({ activeHandle: sessions[0] }, null, 2)); // Sync legacy session file const nextSession = loadSession(sessions[0]); if (nextSession) { fs.writeFileSync(sessionFile, JSON.stringify(nextSession, null, 2)); } ``` ```ts fs.writeFileSync(activeFile, JSON.stringify({ activeHandle: handle }, null, 2)); // Sync legacy session file const userSessionFile = path.join(sessionsDir, `${handle}.json`); if (fs.existsSync(userSessionFile)) { fs.writeFileSync(sessionFile, fs.readFileSync(userSessionFile)); } ``` ### Technical Analysis Successful login sessions are serialized directly to JSON files. The code does not specify restrictive modes when creating the configuration directories or session files. Effective permissions therefore depend on the process umask and permissions inherited from the project directory. The session is duplicated in both a per-user file and the legacy `session.json`, increasing the number of credential-bearing files that must be protected and removed. Writes are also not atomic, which can leave ...[truncated 1207 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
Findings (72)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Outbound webhooks to arbitrary URLs and local persistence for integration queues introduce exfiltration and SSRF-like risk surfaces that are not reflected in the declared purpose. When a skill can both consume external feeds and send arbitrary outbound requests, omission of that capability prevents informed trust decisions by users and operators.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/automation/recycle.ts (reported line 103)May include surrounding context.

ts
const stmt = db.prepare('SELECT * FROM recycle_rules LIMIT 1');
  const rules = stmt.get();
  
  return rules || defaultRules;
}

/**

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comment states mute/cleanup features are disabled, but the cleanup command is immediately implemented and performs live unfollow/block/unblock operations. This mismatch is dangerous because reviewers or users may rely on the comment and underestimate that the code can actively modify the account's follower graph, creating a deceptive or misleading security posture.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Cleanup mode performs destructive bulk unfollow operations without confirmation, preview, or rollback, which can irreversibly alter the account's social graph. Given this skill is explicitly designed for growth automation and resumes a stored session automatically, accidental execution, misuse by someone with local access, or running against the wrong account can cause significant reputational damage and violate user expectations or platform rules.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · sg-post.mjs (reported line 15)May include surrounding context.

js
import { BskyAgent, RichText } from "@atproto/api";
import fs from "fs";

// Load BSKY_* from .env if not already in the environment (so cron/automation works)
try {
  const envText = fs.readFileSync(new URL("./.env", import.meta.url), "utf8");
  for (const line of envText.split("\n")) {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · sg-post.mjs (reported line 17)May include surrounding context.

js
// Load BSKY_* from .env if not already in the environment (so cron/automation works)
try {
  const envText = fs.readFileSync(new URL("./.env", import.meta.url), "utf8");
  for (const line of envText.split("\n")) {
    const m = line.match(/^\s*(BSKY_IDENTIFIER|BSKY_APP_PASSWORD)\s*=\s*(.+)\s*$/);
    if (m && !process.env[m[1]]) process.env[m[1]] = m[2].trim().replace(/^["']|["']$/g, "");

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares required environment variables and clearly implies networked operations, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an authorization gap where the runtime may grant broader access than users expect, especially for a skill that can post content, fetch RSS feeds, and interact with external services.

Content

No source excerpt is available for this finding.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Content

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

clawbsky auth switch # Switch active profile clawbsky auth logout [handle] # Logout a specific or active profile

Run ANY command as a specific user with -u

clawbsky whoami -u other.bsky.social clawbsky post text "Hello!" -u second-account.bsky.social

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This test plan instructs use of real account credentials and includes numerous state-changing actions such as posting, replying, quoting, liking, reposting, and following accounts, but provides no explicit warning about privacy, account reputation, consent, or irreversible side effects. In an agent-executed context, this can lead to unintended public actions on a live social account, exposure or misuse of credentials, and unauthorized modification of account state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code sends user-provided prompts to the Ollama model without any visible user-facing disclosure, consent flow, or warning that social content is being transmitted to an LLM service. In a social-media automation skill, prompts and retrieved content may contain personal, sensitive, or third-party data, so undisclosed transfer creates privacy and trust risks even if the model is local or self-hosted in some deployments.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Untrusted post text and author data are interpolated directly into a natural-language prompt for reply generation, so a crafted post can include instructions that compete with or override the intended task. This can cause the model to produce manipulative, policy-violating, spammy, or irrelevant replies, which is especially risky in an automated social-posting context where generated output may be published with little scrutiny.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Profile descriptions and post text retrieved from Bluesky are treated as trusted prompt content and embedded directly into analysis instructions. An attacker can place adversarial natural-language text in a profile or post to steer the analysis output, potentially causing misleading summaries, policy bypass, or reputational harm if users rely on the result.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The sentiment-analysis prompt includes raw user text directly inside the instruction block, allowing adversarial text to influence the model's behavior or output format despite the JSON request. The impact is somewhat lower because the function only returns a bounded sentiment object, but malformed or manipulated sentiment results can still affect downstream decisions or user trust.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

User-controlled post text is inserted verbatim into the hashtag-generation prompt, so adversarial content can redirect the model to emit unrelated, abusive, or policy-violating hashtags instead of relevant tags. While this does not directly expose secrets or execute code, it can generate harmful public output in a social-media automation workflow.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code transmits the caller-provided text content to an LLM via ollama.chat, which is a data-processing operation with potential privacy implications. While the module comment mentions a local LLM, there is no confirmation prompt, user-facing log, or explicit warning near the call to disclose that supplied content will be sent to the model for analysis.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This function batches potentially sensitive post contents and sends them to ollama.chat for analysis. The file lacks any confirmation prompt, visible disclosure, or warning explaining that multiple user-provided posts will be processed by the model.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function sends historical engagement and follower-count data to a local LLM service without any indication of user consent, minimization, or sensitivity checks. Even if Ollama is usually local, this still transfers potentially sensitive behavioral/account analytics to another processing component, which can create privacy and data-governance risks if the model backend is remote, logged, shared across users, or later reconfigured.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code transmits detailed daily statistics to the LLM for frequency recommendations without any explicit disclosure or access-control context in the file. That exposes operational/account activity data to a secondary processor, which is risky in a multi-user analytics tool because users may not expect their usage history to be shared with an AI subsystem.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The removeCompetitor function performs a delete operation against persistent storage with no confirmation prompt, user-facing log, or warning. Deletions are destructive operations and this file does not provide any visible disclosure or safeguard around removing tracked records.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

The saveSession routine writes authentication session data to local files for later reuse, creating durable credentials on disk. Because this tool is an auth-heavy, multi-user Bluesky CLI, persistent sessions materially increase the chance of account compromise if the host is shared, backed up insecurely, or accessed by other processes.

Content

Scanner excerpt · scripts/auth.ts (reported line 64)May include surrounding context.

ts
}

/**
 * Save session to file
 */
function saveSession(handle: string, session: any): void {
  const userSessionFile = path.join(sessionsDir, `${handle}.json`);

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
sg-post.mjs:6