Back to skill

Security audit

Freelance Pilot

Security checks for vulnerabilities and agentic risk

Overview

FreelancePilot is mostly a coherent freelance bidding helper, but its integration instructions tell agents to run untrusted job text through a shell command pattern that can enable command injection.

Review before installing. The core local code is small and purpose-aligned, but do not paste job descriptions into the documented shell command. Use an argument-array or stdin-based invocation with shell parsing disabled, and avoid adding the SOUL/AGENTS auto-run instructions unless you want persistent behavior for every shared job post.

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

T09 · Insecure Skill Coding Practices

Error
Location
INTEGRATION.md:14
Finding
Shell Command Injection Through Untrusted Job Description Interpolation## Vulnerability Details **File Location**: `INTEGRATION.md:14` **Vulnerability Type**: Shell command injection **Risk Level**: High **Vulnerable Code:** ```markdown 1. **🔍 Analyze First (Don't just reply):** * Run `node freelance-pilot/index.js scan-job "[job text]"` to check for red flags. * If Risk Level is **HIGH**, warn me immediately. Start your reply with: "⚠️ **Caution: High Risk Job Detected**". ``` ### Technical Analysis The integration guide instructs an agent to substitute an untrusted job description directly into a shell command. Job descriptions may be controlled by arbitrary users or third-party job-post authors. Wrapping the input in double quotes does not provide safe shell escaping. Shell constructs such as `$(command)` and backtick command substitution can still be evaluated inside double quotes. An attacker can also use embedded quotes to terminate the intended argument and introduce additional shell syntax. Although `index.js` only treats the resulting values as command-line arguments, injection occurs before Node.js starts if the documented command is executed through a shell. The vulnerability therefore originates in the unsafe invocation pattern documented by the skill. ### Attack Path 1. An attacker creates a job description containing shell syntax, such as `$(attacker_command)`, backticks, or an embedded quote followed by command separators. 2. A user supplies that description to an agent configured with the documented FreelancePilot protocol. 3. Following `INTEGRATION.md`, the agent interpolates the complete text into: ```sh node freelance-pilot/index.js scan-job "[job text]" ``` 4. The agent executes the generated command through a shell. 5. The shell evaluates the injected syntax before or while launching Node.js. 6. The injected command runs with the operating-system privileges and environment available to the agent process. ### Impact Assessment Succ ...[truncated 566 chars]
Remediation
## Remediation Suggestions - Do not interpolate job descriptions or other untrusted content into shell command strings. - Invoke Node.js with an argument-array API that bypasses shell parsing, such as `spawn`, `execFile`, or an equivalent tool interface configured with `shell: false`. - Prefer passing the job description through standard input or a structured JSON input channel, especially because descriptions can be long and contain arbitrary characters. - If a command-line argument is unavoidable, construct the process invocation directly rather than attempting manual shell escaping. - Update the integration instructions to explicitly prohibit executing job-post content as shell syntax. - A safe Node.js invocation pattern is: ```javascript const { spawn } = require('child_process'); const child = spawn( process.execPath, ['freelance-pilot/index.js', 'scan-job', jobText], { shell: false, stdio: ['ignore', 'pipe', 'pipe'] } ); ``` - Treat all job descriptions as attacker-controlled input and run the skill with least privilege in an isolated workspace without unnecessary credentials.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Vague Triggers

Medium
Confidence
91% confidence
Finding
The example usage 'Draft a proposal for this job description...' is a generic phrase that closely matches normal user requests. In systems that infer tool selection from natural language, this can cause the skill to be invoked unintentionally on common text, giving the skill undue control over responses and potentially exposing downstream logic or side effects more often than intended.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The SOUL.md guidance tells the agent to act whenever a user shares a freelance job post and to use output from the skill code to structure the reply. That trigger condition is broad and likely to activate during ordinary conversation, causing unsolicited skill execution and stronger influence over agent behavior than the user may expect. In a marketplace-assistant skill, this increases the chance of prompt/behavior hijacking around common user inputs rather than requiring an explicit tool invocation.