Back to skill

Security audit

Parallel

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Parallel.ai research integration, but it contains under-disclosed high-impact behavior including a hardcoded API key fallback, third-party data transmission, authenticated browsing credential handling, and remote monitor lifecycle actions.

Review before installing. Use only with non-sensitive research data unless you are comfortable sending queries, URLs, and task context to Parallel.ai. Do not rely on the bundled fallback credential; set your own PARALLEL_API_KEY and treat the exposed key as compromised. Avoid passing Browser-Use secrets on the command line, and be cautious with monitor creation, webhook delivery, and delete commands because they affect remote state.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/search.py:14
Finding

Hardcoded Parallel API Credential Used as an Automatic Fallback

Content
View full analysis

Vulnerability Details

File Location: scripts/search.py, line 14
Vulnerability Type: Hardcoded secret / credential exposure
Risk Level: High

Vulnerable Code

python
API_KEY = os.environ.get("PARALLEL_API_KEY", "y2s_m4er5i6-5qCikOLUtmnkvOYRU24eDphq_jg1")

Technical Analysis

A Parallel API credential is embedded directly in the distributed source code. When PARALLEL_API_KEY is absent, the script automatically authenticates with this credential.

Anyone who can download the skill, inspect a deployment artifact, read a source archive, or view repository history can recover the credential. Because the script silently falls back to it, users may also unknowingly submit search queries under the credential owner's account.

The credential cannot be treated as confidential once published. Removing it only from the latest revision is insufficient because it may remain in package copies, caches, forks, logs, and version-control history.

Attack Path

  1. An attacker downloads or otherwise obtains the skill package.
  2. The attacker reads line 14 of scripts/search.py and extracts the embedded key.
  3. The attacker supplies the key to the Parallel SDK or sends requests directly to the Parallel API.
  4. Requests are charged to, logged under, and constrained only by the permissions and quotas of the exposed account.
  5. The attacker can continue consuming the credential until it is revoked or expires.

Alternatively, a user can execute search.py without setting PARALLEL_API_KEY; the script then sends that user's queries through the exposed credential without clearly informing the user.

Impact Assessment

A valid exposed key may allow unauthorized Parallel API usage, quota exhaustion, financial charges, service disruption, and access to account-scoped operations permitted to that key. The exact scope depends on server-side permissions assigned by Parallel.

The issue does not directly grant l ...[truncated 191 chars]

Remediation
View remediation

Remediation Suggestions

  1. Revoke and rotate the exposed credential immediately.

  2. Remove the fallback value and fail closed when the environment variable is absent:

    python
    API_KEY = os.environ.get("PARALLEL_API_KEY")
    if not API_KEY:
        print(
            "Error: PARALLEL_API_KEY environment variable is required",
            file=sys.stderr,
        )
        sys.exit(1)
    
  3. Purge the secret from version-control history and previously published artifacts where practical.

  4. Search account telemetry for unauthorized use, unexpected source addresses, abnormal costs, and quota spikes.

  5. Store deployment credentials in a dedicated secret manager or protected environment configuration.

  6. Add automated secret scanning and pre-commit or CI checks to prevent future credential publication.

  7. Use narrowly scoped, short-lived credentials and configure spending or rate limits where supported.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/parallel.sh:12
Finding

User Input Is Interpolated Directly into a JSON Request Body

Content
View full analysis

Vulnerability Details

File Location: scripts/parallel.sh, lines 12-20
Vulnerability Type: JSON injection and request-structure manipulation
Risk Level: Medium

Vulnerable Code

bash
run_task() {
  local input="$1"
  local processor="${2:-base}"
  
  # Submit
  local response=$(curl -s -X POST "$BASE_URL/tasks/runs" \
    -H "x-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"processor\": \"$processor\", \"input\": \"$input\"}")

The values are populated from command-line arguments in the command handlers, including:

bash
research)
  QUERY="$*"
  [ -z "$QUERY" ] && { echo "Usage: parallel.sh research <query>" >&2; exit 1; }
  run_task "$QUERY" "base"
  ;;

Technical Analysis

The script constructs JSON by concatenating unescaped shell variables into a quoted string. Quotation marks, backslashes, control characters, and JSON structural characters inside input are not JSON-encoded.

This is not direct local shell-command injection because the variable expansion remains inside shell quotes. It is nevertheless a request injection issue: crafted input can terminate the intended JSON string, add or replace fields, or make the request malformed. Depending on the API parser's duplicate-key behavior and supported task fields, an attacker may manipulate processing options beyond those intended by the wrapper.

Even ordinary queries containing quotation marks or newlines can produce invalid JSON, resulting in unreliable behavior and failed requests.

Attack Path

  1. An attacker supplies a crafted research query through an agent request or another interface that forwards text to parallel.sh.
  2. The query contains a closing quotation mark followed by additional JSON properties and a trailing value designed to balance the final generated JSON.
  3. The shell inserts the string verbatim into the curl -d argument.
  4. The Pa ...[truncated 728 chars]
Remediation
View remediation

Remediation Suggestions

Construct the payload with a JSON-aware tool rather than string interpolation. For example:

bash
local payload
payload=$(jq -n \
  --arg processor "$processor" \
  --arg input "$input" \
  '{processor: $processor, input: $input}')

local response
response=$(curl --fail-with-body --silent --show-error \
  -X POST "$BASE_URL/tasks/runs" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary "$payload")

Additionally:

  1. Validate processor against an explicit allowlist.
  2. Apply reasonable input-length limits to prevent excessive API usage.
  3. Use curl --fail-with-body --silent --show-error and verify HTTP status codes.
  4. Avoid storing large API responses in shell variables when not necessary.
  5. Add tests containing quotation marks, backslashes, newlines, Unicode, and JSON-like user input.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/task.py:170
Finding

Browser-Use API Secret Can Be Supplied in Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/task.py, lines 170-172 and 231-239
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
parser.add_argument("--browseruse-key", metavar="KEY",
                   help="browser-use.com API key for authenticated page access")

The supplied value is subsequently placed into an authorization header:

python
# Build MCP servers for authenticated browsing
mcp_servers = None
browseruse_key = args.browseruse_key or os.environ.get("BROWSERUSE_API_KEY")
if browseruse_key:
    mcp_servers = [{
        "type": "url",
        "url": "https://api.browser-use.com/mcp",
        "name": "browseruse",
        "headers": {"Authorization": f"Bearer {browseruse_key}"}
    }]

Technical Analysis

Accepting a secret through --browseruse-key places it in the process command line. Command-line arguments may be captured by shell history, terminal transcripts, job runners, monitoring software, audit systems, crash reports, and process-inspection interfaces such as ps or /proc.

The code supports the safer BROWSERUSE_API_KEY environment variable, but the command-line option remains available and is explicitly presented as a credential input mechanism.

The resulting authorization header is also embedded into the MCP server configuration passed to the Parallel task API. This means the Browser-Use bearer credential is transmitted as part of the task creation request to the Parallel service, rather than being sent only to the Browser-Use endpoint. That disclosure must be intentional, documented, and supported by the trust model of both services.

Attack Path

  1. A user runs task.py --browseruse-key SECRET ....
  2. The full invocation is stored in shell history or remains visible in process metadata while the script is running.
  3. Another local process, monitoring agent, job ...[truncated 1013 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the --browseruse-key argument and accept the credential only through a protected environment variable, secret file descriptor, or secret manager.
  2. If interactive entry is necessary, use getpass.getpass() so the value is not echoed or included in process arguments.
  3. Warn users that previously used command-line secrets may remain in shell history and should be rotated.
  4. Verify that the Parallel API's MCP integration requires the bearer token to be included in the task configuration.
  5. Clearly document that the Browser-Use key is transmitted to Parallel when MCP integration is enabled.
  6. Prefer short-lived and narrowly scoped Browser-Use credentials.
  7. Ensure exception handling, SDK debug logging, and telemetry never serialize or print the headers field.
  8. Add redaction rules for Authorization, BROWSERUSE_API_KEY, and related task configuration fields.

T08 · Insecure Dependencies

Note
Location
SKILL.md:32
Finding

Third-Party SDK Installation Is Unpinned and Lacks an Integrity-Locked Dependency Manifest

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 32-36
Vulnerability Type: Unpinned third-party dependency
Risk Level: Low

Vulnerable Code

markdown
## Setup

```bash
pip install parallel-web
text

### Technical Analysis

The installation instructions request the latest available `parallel-web` release from the package index without a version constraint or cryptographic integrity hash. The project does not include a requirements or lock file in the audited directory.

Consequently, two installations performed at different times may execute different dependency code. If a future upstream release is compromised, the package account is taken over, or the distribution channel serves a malicious artifact, users following the documented setup command may install attacker-controlled code.

The audit did not establish that the current `parallel-web` package is malicious. The confirmed issue is the absence of reproducible version and integrity controls.

### Attack Path

1. An attacker compromises the upstream package publisher or package-distribution path, or a malicious release is otherwise published under the expected package name.
2. A user follows the documented `pip install parallel-web` instruction.
3. `pip` resolves the newest matching release because no version is pinned.
4. Package installation or later import executes the compromised dependency code in the user's Python environment.
5. That code receives the privileges of the user running the skill and may access environment variables such as `PARALLEL_API_KEY`.

This path is conditional on upstream or distribution compromise; no such compromise was demonstrated during this source audit.

### Impact Assessment

A compromised dependency could execute arbitrary Python code with the invoking user's privileges. It could read accessible files and environment credentials, modify the virtual environment, alter API requests or responses, and
...[truncated 186 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin parallel-web to a reviewed exact version.
  2. Maintain a dependency manifest generated by a locking tool such as pip-tools, Poetry, or uv.
  3. Require cryptographic hashes for downloaded artifacts where the deployment workflow supports them.
  4. Install dependencies inside an isolated virtual environment with minimal operating-system privileges.
  5. Use automated dependency vulnerability and provenance scanning in CI.
  6. Review release notes and package ownership before upgrading the locked version.
  7. Keep setup documentation synchronized with the lock file and provide a reproducible installation command.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

Tainted flow: 'headers' from os.environ.get (line 28, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/monitor.py (reported line 36)May include surrounding context.

python
url = f"{BASE_URL}{endpoint}"
    
    if method == "GET":
        response = requests.get(url, headers=headers, params=data)
    elif method == "POST":
        response = requests.post(url, headers=headers, json=data)
    elif method == "DELETE":

Tainted flow: 'headers' from os.environ.get (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/monitor.py (reported line 38)May include surrounding context.

python
if method == "GET":
        response = requests.get(url, headers=headers, params=data)
    elif method == "POST":
        response = requests.post(url, headers=headers, json=data)
    elif method == "DELETE":
        response = requests.delete(url, headers=headers)
    else:

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description centers on search and research capabilities: finding information on the web, providing citations, and supporting agentic multi-step reasoning. The supplied code instead only calls Parallel.ai's extract endpoint on user-provided URLs to retrieve excerpts or full content. There is no code for querying a search index, discovering URLs, ranking search results, generating citations, or coordinating multi-step reasoning. This is a materially different primary purpose, so the description does not accurately represent the code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description says this skill performs web search and research with rich excerpts, citations, and agentic multi-step reasoning. However, the supplied code does not perform search-result retrieval, citation handling, excerpt extraction, or any explicit research workflow. Instead, it uses client.beta.findall.ingest/create/retrieve to transform a query into structured matching criteria and return matched entities/candidates, optionally enriched with fields like funding or employee count. This is a materially different primary purpose: structured entity/list discovery rather than high-accuracy web research. No harmful undeclared permissions are present, but the core functionality is misrepresented.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description emphasizes on-demand web search and research capabilities, including rich excerpts, citations, and agentic reasoning. However, the supplied code does not implement search or research queries directly. Instead, it manages persistent monitoring resources through the Parallel.ai Monitor API, allowing users to track topics over time, receive webhook alerts, inspect monitor events, and delete monitors. This is a materially different primary purpose from a search/research skill. No suspicious extra permissions are visible, but the functional scope is clearly mismatched.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README states that the skill performs web searches through Parallel.ai but does not clearly warn that user prompts, search queries, and possibly sensitive research context will be transmitted to a third-party service. In an agent setting, users may assume queries stay local to the host platform, so the missing disclosure can lead to inadvertent exfiltration of confidential data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill uses sensitive capabilities including environment variables, network access, and shell execution, but does not declare any tool scope or permission boundaries. This increases the chance that hosts or users invoke it without understanding its external connectivity and code execution requirements, weakening least-privilege controls and auditability.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description does not clearly warn that user queries are transmitted to an external third-party service, despite the skill being fundamentally a hosted web search integration. This can cause inadvertent disclosure of sensitive prompts, internal data, or proprietary research topics to Parallel.ai without informed user consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger phrase "research" is extremely broad and may cause the skill to activate on many unrelated user requests. Because the skill sends queries to a third-party API, overbroad triggering can lead to unintended data disclosure, unnecessary external calls, and user confusion about when outside services are being used.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/monitor.py (reported line 38)May include surrounding context.

python
if method == "GET":
        response = requests.get(url, headers=headers, params=data)
    elif method == "POST":
        response = requests.post(url, headers=headers, json=data)
    elif method == "DELETE":
        response = requests.delete(url, headers=headers)
    else:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes a web search and research skill, including agentic reasoning, but this file implements persistent monitor creation with scheduled cadence and outbound webhook notifications. Continuous tracking and alert delivery are materially different from one-off search/research behavior and are not mentioned in the stated skill description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The delete command performs an irreversible remote action immediately from a single CLI argument, with no confirmation prompt, dry-run mode, or other guardrail. In an agent setting, accidental invocation, prompt confusion, or parameter mix-ups could delete the wrong monitor and disrupt ongoing tracking or alerting.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/monitor.py (reported line 23)May include surrounding context.

python
set -e

API_KEY="${PARALLEL_API_KEY:?Error: PARALLEL_API_KEY environment variable is required}"
BASE_URL="https://api.parallel.ai/v1"
MAX_WAIT="${PARALLEL_MAX_WAIT:-120}"

# Submit task and poll for result

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/parallel.sh (reported line 8)May include surrounding context.

sh
set -e

API_KEY="${PARALLEL_API_KEY:?Error: PARALLEL_API_KEY environment variable is required}"
BASE_URL="https://api.parallel.ai/v1"
MAX_WAIT="${PARALLEL_MAX_WAIT:-120}"

# Submit task and poll for result

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

This POST request transmits user-controlled input to an external service, creating a real data egress path from the agent environment to a third party. The danger is contextual rather than exploit-code driven: if prompts contain secrets, personal data, or proprietary information, the skill will disclose them outside the trust boundary.

Content

Scanner excerpt · scripts/parallel.sh (reported line 17)May include surrounding context.

sh
local processor="${2:-base}"
  
  # Submit
  local response=$(curl -s -X POST "$BASE_URL/tasks/runs" \
    -H "x-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"processor\": \"$processor\", \"input\": \"$input\"}")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script sends arbitrary research queries and entity names directly to a third-party API, which can expose sensitive user, customer, or internal business information without any explicit privacy notice or consent mechanism. In an agent skill context, users may reasonably assume local processing, so silent external transmission increases the risk of unintended data disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sends user queries directly to the external Parallel.ai API without any disclosure, consent prompt, or warning that submitted text leaves the local environment. In an agent skill context, users or upstream agents may pass sensitive prompts, internal URLs, credentials, or proprietary research terms, causing unintended data exfiltration to a third party.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

When a browser-use API key is present, the script silently enables an external MCP server for authenticated browsing and forwards user queries plus potentially sensitive page contents to a third-party service. In an agent skill context, this is risky because execution may occur without a clear runtime disclosure or consent checkpoint, increasing the chance of unintentionally sending internal URLs, credentials-adjacent data, or proprietary content off-platform.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The code configures an outbound connection to https://api.browser-use.com/mcp and includes a bearer token in the Authorization header, causing task inputs and authenticated browsing activity to be transmitted to an external service. External transmission is expected for this skill's purpose, but it still represents a real data exposure risk if users are not clearly informed or if sensitive targets are processed through the service.

Content

Scanner excerpt · scripts/task.py (reported line 235)May include surrounding context.

python
if browseruse_key:
        mcp_servers = [{
            "type": "url",
            "url": "https://api.browser-use.com/mcp",
            "name": "browseruse",
            "headers": {"Authorization": f"Bearer {browseruse_key}"}
        }]

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest presents the skill as a search/research capability, but this code also performs destructive remote state changes by deleting existing monitors. While monitor management may relate to the API, destructive lifecycle operations are not implied by the current description.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module usage docstring documents the mode flag as accepting only 'one-shot' or 'agentic'. However, the argument parser actually allows a third mode, 'fast', which means the inline documentation does not accurately describe the implemented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.