Back to skill

Security audit

GEO Optimization

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a GEO guidance and monitoring tool, but its automation is under-scoped and includes broad local secret loading, third-party API transmission, cron-style persistence, and insecure shell handling.

Install only if you are comfortable with a Perplexity-backed monitoring script that sends your test queries to Perplexity and saves responses locally. Review and edit the scripts before running cron: restrict .env loading to PERPLEXITY_API_KEY, remove the hardcoded /Users/awalker/clawd path, replace the fixed /tmp file with mktemp, and avoid embedding filenames into python3 -c source.

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

Warning
Location
scripts/geo-daily-monitor.sh:14
Finding

Predictable Temporary File Allows Symlink-Based File Truncation

Content
View full analysis
/tmp/geo-test-output.txt 2>&1 ``` ### Technical Analysis The monitoring wrapper redirects command output to the fixed, predictable path `/tmp/geo-test-output.txt`. Shared temporary directories are normally writable by other local users, and shell redirection follows symbolic links. A local attacker who can create files in `/tmp` could create `/tmp/geo-test-output.txt` as a symbolic link to another file writable by the account running this script. When the scheduled monitoring job starts, the shell opens the symlink target with truncation enabled before executing Python. The risk is elevated when the script is run through cron or another scheduler under an account with access to files the attacker cannot modify directly. The temporary file does not require a stable name for the Skill's declared functionality, so using a shared predictable path exceeds minimum-safe file privileges. ### Attack Path 1. The attacker identifies that the daily monitoring wrapper runs periodically. 2. The attacker creates a symbolic link at the predictable path: ```bash ln -s /path/to/target /tmp/geo-test-output.txt ``` 3. The scheduled job runs `geo-daily-monitor.sh`. 4. Shell redirection follows the symbolic link and opens the target file with truncation enabled. 5. The target is erased or replaced with GEO monitoring output. Exploitation requires local access and a target file writable by the account executing the monitoring job. ### Impact Assessment Successful exploitation can truncate or corrupt any file writable by the scheduled job's account. Possible consequences include loss of application data, corrupted configuration, denial of service, or modification of operational files. This issue does not independently grant privile ...[truncated 200 chars]
Remediation
View remediation
"$OUTPUT_FILE" 2>&1 SUMMARY=$(tail -50 "$OUTPUT_FILE" | grep -A 20 "SUMMARY REPORT" || echo "Test completed") ``` Additional hardening measures: - Run the scheduled job under a dedicated, unprivileged service account. - Do not use a fixed filename in a globally writable directory. - Apply a restrictive `umask`, such as `umask 077`, near the start of the script. - If persistent logs are required, store them in an application-owned directory with restrictive permissions instead of `/tmp`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/geo-daily-monitor.sh:24
Finding

Filesystem-Derived Filename Is Interpolated into Executable Python Source

Content
View full analysis
/dev/null | head -1) if [ -f "$LATEST_SUMMARY" ]; then # Extract key metrics using Python METRICS=$(python3 -c " import json with open('$LATEST_SUMMARY') as f: data = json.load(f) ``` ### Technical Analysis `LATEST_SUMMARY` is derived from a filename in the `geo-history` directory and is inserted directly into source code passed to `python3 -c`. The filename is placed inside a single-quoted Python string: ```python with open('$LATEST_SUMMARY') as f: ``` A filename containing a single quote, newline, or suitable Python syntax can terminate the intended string literal and introduce attacker-controlled Python statements. Shell quoting around the overall `python3 -c` argument does not protect the generated Python program from this source-code injection. The use of `ls` output for programmatic filename selection is also unsafe because filenames can contain whitespace and newline characters. No source-code generation is required for the declared report-processing functionality; the filename should be passed as data through a positional argument. ### Attack Path 1. The attacker obtains write access to the `geo-history` directory. This could occur through shared workspace permissions or another compromised process using the same account. 2. The attacker creates a `summary-*.json` entry whose filename contains characters that terminate the Python string and inject Python syntax. 3. The attacker makes the malicious entry the newest matching summary file. 4. The wrapper selects it through: ```bash ls -t geo-history/summary-*.json | head -1 ``` 5. The selected filename is interpolated into the argument supplied to `python3 -c`. 6. Pyth ...[truncated 880 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Tainted flow: 'api_key' from os.getenv (line 51, 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/geo-monitor.py (reported line 59)May include surrounding context.

python
import requests
    
    try:
        response = requests.post(
            "https://api.perplexity.ai/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared purpose is GEO optimization guidance, but the file also instructs operational monitoring, cron execution, local file handling, report generation, and API-driven testing. This mismatch is dangerous because users and policy systems may approve the skill expecting passive content advice while it actually drives active automation that can access local resources, external services, and scheduled execution.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

Reading a local .env file is a credential-access capability and can pull secrets into the process without least-privilege controls. In a skill ecosystem, that is more dangerous because users may run the script in repositories containing multiple unrelated secrets, any of which become available to the process once loaded.

Content

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

python
from pathlib import Path
import subprocess

# Load .env file
def load_env():
    env_path = Path(__file__).parent.parent / ".env"
    if env_path.exists():

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

Opening and parsing .env directly gives the script local secret-reading behavior that may exceed user expectations for a monitoring utility. The danger is not exfiltration shown in this line alone, but unnecessary expansion of secret access and the possibility of accidental exposure through future code changes or debugging.

Content

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

python
# Load .env file
def load_env():
    env_path = Path(__file__).parent.parent / ".env"
    if env_path.exists():
        with open(env_path) as f:
            for line in f:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises content optimization guidance but also includes executable monitoring workflows that imply use of shell, network access, file read/write, and environment secrets without declaring any explicit tool scope. Undeclared capabilities make the skill harder to review safely and can lead an agent to grant broader access than users expect, especially where scripts call external APIs and scheduled jobs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes GEO analysis/optimization for LLM discoverability, but this file imports subprocess and documents using an external 'clawdbot' CLI to perform searches. Spawning external tools is a materially broader capability than simple GEO analysis and is not clearly justified by the stated purpose, especially since the implementation otherwise uses direct HTTP requests.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script automatically loads a local .env file and imports any key-value pairs into the process environment, which broadens access to local secrets beyond what users may expect. In a skill context, implicit secret loading increases the risk of unauthorized credential use or accidental reuse of unrelated secrets if the file contains more than the needed API key.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script transmits user-supplied queries to a third-party API and does so without an explicit warning or consent prompt at the point of use. If users include sensitive internal prompts, customer data, or proprietary research terms, that information is exposed outside the local environment in a way that may not be obvious from normal execution.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The request includes both the user query payload and a bearer token in headers to an external service, making this a genuine data egress operation. Although standard for API integrations, the risk is that users may not realize their prompts are leaving the system and being associated with a credentialed account.

Content

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

python
import requests
    
    try:
        response = requests.post(
            "https://api.perplexity.ai/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The request includes both the user query payload and a bearer token in headers to an external service, making this a genuine data egress operation. Although standard for API integrations, the risk is that users may not realize their prompts are leaving the system and being associated with a credentialed account.

Content

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

python
import requests
    
    try:
        response = requests.post(
            "https://api.perplexity.ai/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

The hardcoded Perplexity endpoint confirms outbound communication to a third-party domain. In this skill, that behavior is expected for search visibility monitoring, but it still represents a real privacy and governance risk if used with sensitive or internal-only query content.

Content

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

python
try:
        response = requests.post(
            "https://api.perplexity.ai/chat/completions",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script persists full queries, returned content, and citations to local JSON files without clearly warning the user. This can create an unintended local data-retention risk, especially if queries or responses contain confidential business information, customer details, or sensitive research topics.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The function documentation and adjacent comment state that the code calls Perplexity through Clawdbot's web_search tool. However, the actual implemented path performs a direct HTTPS POST to api.perplexity.ai and never invokes the constructed CLI command, so the inline intent description contradicts the real behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.