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## 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
## Remediation Suggestions 1. Load persisted state before processing commands: ```javascript const profiles = loadProfiles(); ``` 2. Remove the current `const profiles = [];` initialization from `run()`. 3. Validate that the parsed value is an array before using or saving it. 4. Implement atomic persistence by writing to a temporary file and renaming it only after a successful write. 5. Introduce file locking or another concurrency-control mechanism so simultaneous signups cannot overwrite each other's updates. 6. Preserve a backup before replacing the database and recover gracefully from malformed JSON. 7. 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## 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
## 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
Content
}
```

2. Update SKILL.md with new commands
3. Test thoroughly
4. Document in README
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.

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.

Context-Inappropriate Capability

High
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.

Missing User Warnings

Medium
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.

Vague Triggers

Medium
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.

Vague Triggers

Medium
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.

Vague Triggers

Medium
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.

Missing User Warnings

Medium
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.

Intent-Code Divergence

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Description-Behavior Mismatch

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Low
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.

Intent-Code Divergence

Low
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.

Static analysis

No suspicious patterns detected.