Back to skill

Security audit

Job Hunter

Security checks for vulnerabilities and agentic risk

Overview

This job-search skill is coherent overall, but one bundled search script has an unsafe command-execution vulnerability and the skill stores personal job-search profile data without clear privacy controls.

Review before installing. Use this skill only in a workspace where saving job-search profile data is acceptable, avoid putting highly sensitive personal information in profile.json, and do not run artifact/scripts/search_jobs.sh until its Python interpolation issues are fixed. If you use Brave search, assume search terms and location details may be sent to Brave via the configured API key.

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
scripts/search_jobs.sh:31
Finding

Arbitrary Code Execution Through Python Source Injection

Content
View full analysis
/dev/null || echo "$ALL_RESULTS") ``` Finally, the user-controlled `--limit` value is inserted as an executable Python expression: ```bash # Trim to limit echo "$ALL_RESULTS" | python3 -c " import json, sys results = json.load(sys.stdin)[:${LIMIT}] print(json.dumps(results, indent=2)) " ``` ### Technical Analysis The script builds Python programs using shell-expanded strings and passes them to `python3 -c`. Values such as `QUERY`, `sq`, `ALL_RESULTS`, and `LIMIT` are treated as Python source code instead of data. Quoting the shell variable does not make interpolation into Python source safe. An attacker can include Python quote delimiters, statement separators, expressions, and comments in an argument. Once interpolated, these characters can terminate the intended string or slice expression and append arbitrary Python statements. The vulnerable data flows are: 1. The first positional command-line argument is assigned to `QUERY`. 2. `QUERY` is placed inside a s ...[truncated 4084 chars]
Remediation
View remediation
&2 exit 2 fi if [[ ! "$LIMIT" =~ ^[0-9]+$ ]]; then printf 'Error: --limit must be a non-negative integer\n' >&2 exit 2 fi ``` Pass the validated limit as an argument rather than interpolating it: ```bash echo "$ALL_RESULTS" | python3 -c ' import json import sys limit = int(sys.argv[1]) results = json.load(sys.stdin)[:limit] print(json.dumps(results, indent=2)) ' "$LIMIT" ``` A reasonable upper bound should also be enforced to prevent excessive resource consumption: ```bash if (( LIMIT > 100 )); then printf 'Error: --limit must not exceed 100\n' >&2 exit 2 fi ``` ### 3. Merge JSON without embedding it into source Provide both JSON documents through files, separate file descriptors, or arguments. A robust option is to use temporary files created securely: ```bash tmp_all=$(mktemp) tmp_parsed=$(mktemp) trap 'rm -f "$tmp_all" "$tmp_parsed"' EXIT printf '%s' "$ALL_RESULTS" > "$tmp_all" printf '%s' "$PARSED" > "$tmp_parsed" ALL_RESULTS=$( python3 - "$tmp_all" "$tmp_parsed" <<'PY' import json import sys with open(sys.argv[1], encoding="utf-8") as handle: existing = js ...[truncated 1134 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes network access (web_search) and shell commands, but it does not declare any explicit tool scope or permissions. That creates an overbroad execution surface where an agent may use capabilities beyond what a user or platform reviewer would reasonably expect, reducing containment and auditability.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation description is very broad and overlaps with many ordinary career-help requests, which can cause the skill to trigger in situations where the user did not intend to invoke file-writing, web searching, or shell-assisted workflows. In context, this increases the chance that higher-risk capabilities are brought into routine conversations without clear user awareness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill directs the agent to collect and save a detailed candidate profile to profile.json without warning that it may contain sensitive personal and employment data such as location, salary expectations, exclusions, and career history. Persisting that information by default increases privacy risk, accidental retention, and possible downstream exposure to other tools or processes in the workspace.

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/search_jobs.sh (reported line 68)May include surrounding context.

sh
for sq in "${SEARCH_QUERIES[@]}"; do
        ENCODED_SQ=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$sq'))")
        RESPONSE=$(curl -s "https://api.search.brave.com/res/v1/web/search?q=${ENCODED_SQ}&count=10&freshness=${FRESHNESS}" \
            -H "Accept: application/json" \
            -H "X-Subscription-Token: ${BRAVE_API_KEY}" 2>/dev/null || echo '{}')

Vague Triggers

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This JSON manifest/template contains many generic profile fields but does not specify when or how it is intended to be used, nor any constraints or negative examples limiting activation or applicability. For manifest-scope review under vague triggers, the absence of any explicit trigger scope can lead to overly broad interpretation of when this profile template should apply.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script sends the user-provided job search query and optional location to an external web API via curl when BRAVE_API_KEY is set. While the header comments mention Brave API availability, there is no runtime confirmation, warning, or user-facing notice that query data will be transmitted to a third-party service.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.