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

Content
View full analysis

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
View 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
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.