Back to skill

Security audit

Plenty of Claws

Security checks for vulnerabilities and agentic risk

Overview

This skill is not malicious, but its profile storage is poorly controlled and can silently erase stored profiles.

Review this before installing if you care about preserving profile data. It stores profile records locally, but the main runtime can overwrite existing profiles during signup and the documented test commands can delete the local profile file. Do not run the included tests against real data, and install only if you are comfortable with local, non-sensitive profile records and possible data loss until the persistence bug is fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
index.js:31
Finding

Signup Overwrites the Entire Persistent Profile Database

Content
View full analysis

Vulnerability Details

File Location: index.js:27-31, 44-65
Vulnerability Type: Persistent data integrity failure caused by unsafe state initialization
Risk Level: High

Vulnerable Code

javascript
export async function run(context) {
  const input = (context.input || "").trim();
  const lower = input.toLowerCase();
  const clawId = getClawId(context);

  const profiles = [];
javascript
  if (lower.startsWith("sign up")) {
    // Extract details from context
    const name = context.name || context.agent?.name || "Unknown Agent";
    const agentType = context.agent?.type || "AI Agent";
    
    // Check if profile already exists
    const existingProfile = profiles.find(p => p.id === clawId);
    if (existingProfile) {
      return success(`Hey ${name}! Your profile already exists. Use 'View profile' to see it, or contact me to update it.`);
    }

    // Create new profile
    const newProfile = {
      id: clawId,
      name: name,
      type: agentType,
      status: "active",
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      traits: [],
      bio: "",
      interests: []
    };

    profiles.push(newProfile);
    saveProfiles(profiles);

Technical Analysis

The application defines a loadProfiles() function but does not invoke it from the production run() handler. Instead, every invocation initializes profiles as a new empty array.

Consequently:

  1. Duplicate-profile checks always run against an empty collection.
  2. Profile browsing cannot display persisted records.
  3. A signup appends one profile to the empty array.
  4. saveProfiles(profiles) serializes that one-element array over the existing JSON database.

This is a destructive state-management flaw. Any previously persisted profiles are silently discarded when a signup command succeeds. It directly contradicts the documented persistent-storage behavior.

Attack Path

  1. The profile database contains o ...[truncated 1163 chars]
Remediation
View remediation

Remediation Suggestions

  1. Load persisted state before processing commands:
javascript
const profiles = loadProfiles();
  1. Remove the current const profiles = []; initialization from run().
  2. Validate that the parsed value is an array before using or saving it.
  3. Implement atomic persistence by writing to a temporary file and renaming it only after a successful write.
  4. Introduce file locking or another concurrency-control mechanism so simultaneous signups cannot overwrite each other's updates.
  5. Preserve a backup before replacing the database and recover gracefully from malformed JSON.
  6. Add integration tests that execute the exported production run() function and confirm that signup preserves all existing records.

T09 · Insecure Skill Coding Practices

Warning
Location
test.js:124
Finding

Documented Test Utilities Reset and Delete the Persistent Profile Store

Content
View full analysis

Vulnerability Details

File Location: test.js:124-126, 232; manual-test.js:123, 173; README.md:96-103
Vulnerability Type: Destructive test behavior without storage isolation
Risk Level: Medium

Vulnerable Code

test.js deletes the existing profile file before testing and deletes the resulting file again during cleanup:

javascript
// Clear any existing profiles
if (fs.existsSync(PROFILE_PATH)) {
  fs.unlinkSync(PROFILE_PATH);
}
javascript
// Clean up
fs.unlinkSync(PROFILE_PATH);

manual-test.js resets the same profile path and later removes it:

javascript
// Test 2: View all profiles
console.log("\n📝 Test 2: View all profiles");
fs.writeFileSync(PROFILE_PATH, JSON.stringify([], null, 2)); // Reset
const test2 = runTest({
  input: "view profile"
});
javascript
// Clean up
fs.unlinkSync(PROFILE_PATH);

The README directly instructs developers to execute these scripts:

bash
# Navigate to skill directory
cd skills/plenty-of-claws

# Run tests
node test.js

# Or run manual tests
node manual-test.js

Technical Analysis

Both test utilities derive PROFILE_PATH from their own directory:

javascript
const PROFILE_PATH = path.join(__dirname, "profiles.json");

That is also the documented location of the skill's persistent profile database. The tests do not use a temporary directory, injected test path, mock filesystem, backup, or restoration procedure.

test.js explicitly deletes any pre-existing database before installing fixtures and then unconditionally deletes the file during cleanup. manual-test.js overwrites the database with an empty array during execution and then deletes it. The cleanup calls are not protected by existence checks or try/finally, which can additionally produce inconsistent cleanup behavior when tests fail.

Because these commands are presented as the supported local testing procedure, a developer following the documentation can unintentionally destro ...[truncated 1272 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create a unique temporary directory for every test run, for example with fs.mkdtempSync().
  2. Refactor the production implementation so the profile path can be injected through an explicit test-only configuration parameter.
  3. Ensure tests never default to the production profiles.json path.
  4. Perform cleanup in a finally block and restrict deletion to the verified temporary directory.
  5. Add a safety check that refuses destructive test setup when the selected path is the installed skill directory.
  6. If tests must operate on an existing file, create a backup first and restore it byte-for-byte after testing.
  7. Update the README to explain that tests use isolated temporary storage.
  8. Import and test the actual exported run() function instead of maintaining duplicated implementations that can diverge from production behavior.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • 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 (16)

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · README.md (reported line 156)May include surrounding context.

}

text

2. Update SKILL.md with new commands
3. Test thoroughly
4. Document in README

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill metadata and documentation claim matchmaking/search capabilities and safe profile browsing, but the documented behavior indicates features are missing or broken and that filesystem persistence is used without clearly declared resources. This can mislead users and integrators about what the skill actually does, causing unsafe trust assumptions around data handling and functionality.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script deletes profiles.json, recreates it with test data, and exits the process, none of which are justified by the stated dating-profile functionality. In a real agent or shared workspace, running this file could irreversibly destroy stored profiles and disrupt surrounding processes or automation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README advertises persistent storage in profiles.json but does not clearly warn users that profile data is written locally and retained across sessions. This can create privacy and consent issues, especially in a dating-style context where bios, traits, and interests may be considered sensitive metadata.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documented trigger phrase "Sign up" is extremely generic and could be invoked during ordinary conversation, causing the skill to activate unintentionally. In a skill that creates persistent profiles, accidental activation can lead to unintended data creation or profile registration without clear user intent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The phrase "View profile" is also broad and ambiguous, making accidental activation likely in normal chat or when discussing profiles generally. Because this skill exposes stored profile information, unintended triggering could reveal local profile data to users who did not explicitly request the skill.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

A trigger as broad as Help can be activated during ordinary conversation, causing the skill to run when the user did not intend to invoke it. In agent environments, overly generic triggers increase prompt-squatting risk and can interfere with other skills or normal assistant behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill states that profiles are persistently stored in profiles.json but does not clearly warn users at the point of collection that their data will be retained across sessions. Because this is a dating-style profile system, the stored content may include personal or sensitive profile information, making undisclosed retention more risky in context.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comments on loadProfiles and saveProfiles state that profiles are loaded from and saved to a file. However, run initializes const profiles = []; and never calls loadProfiles, so sign-up checks, searches, and browsing do not actually operate on previously stored profiles. This is an intent/documentation contradiction rather than a mere missing detail because the code claims persistence semantics it does not honor in practice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill stores dating-profile data on disk in profiles.json without telling users their profile information will be persisted. In the context of a social/dating skill, this increases privacy risk because users may share personal or identifying information in bios and interests without informed consent or retention expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code creates and updates a local profiles.json file via fs.writeFileSync, which persists user-related profile data. Although this is a manual test file, there is no confirmation prompt or user-facing disclosure near the write operations explaining that profile information will be stored on disk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This file is a destructive local test harness embedded in the skill repository rather than functionality needed for a dating-profile skill. It resets shared state, mutates on-disk data, and controls process termination, which creates a risk of accidental data loss or unsafe execution if run in an environment where profiles.json contains real user data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The test setup silently deletes and recreates profiles.json with no runtime warning or confirmation, which is unsafe for a skill handling user profile data. Because the skill context implies persistence of social/dating profiles, this behavior is more dangerous than in a purely ephemeral test utility.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The cleanup step irreversibly removes profiles.json at the end of execution without user awareness, causing silent loss of all persisted profiles. In the context of a dating-profile skill, this undermines expected data retention and could wipe legitimate user content if the script is run in the wrong environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The cleanup step removes profiles.json with fs.unlinkSync, which is a destructive file operation. While this is test code, the surrounding comments do not clearly warn users that running the script will delete the local profile file at the end.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The comment downplays the behavior as clearing existing profiles, but the implementation deletes the entire backing file whenever it exists. Misleading comments increase the chance that maintainers or operators run the script without appreciating that it performs irreversible deletion.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.