Back to skill

Security audit

Local Deep Research

Security checks for vulnerabilities and agentic risk

Overview

This local research skill is mostly coherent, but it should be reviewed because its shell script can execute a sourced .env file and may send credentials to an insufficiently constrained login URL.

Install only if you control the LDR service and can run the skill in a constrained environment. Prefer environment variables over the .env path, verify that any LDR .env is private and contains only simple trusted assignments, keep LDR_BASE_URL and LDR_LOGIN_URL on the same trusted local origin, and use a dedicated low-privilege LDR account with a unique password.

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

Error
Location
scripts/ldr-research.sh:24
Finding
Arbitrary Shell Execution Through Sourced Environment File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ldr-research.sh`, lines 24–30 **Vulnerability Type**: Unsafe execution of a configuration file **Risk Level**: High ### Vulnerable Code ```bash LDR_ENV="${LDR_CONFIG_DIR:-$HOME/.config/local_deep_research/config}/.env" if [[ -f "$LDR_ENV" ]]; then set -a # shellcheck source=/dev/null source "$LDR_ENV" set +a fi ``` ### Technical Analysis The script loads the selected `.env` file with Bash's `source` command. This does not treat the file as passive key-value configuration: it parses and executes its entire contents as shell code. The location is also influenced by the `LDR_CONFIG_DIR` environment variable. Therefore, an attacker who can modify the default `.env`, control `LDR_CONFIG_DIR`, or place a malicious file in a selected directory can execute arbitrary shell commands when any Skill action starts. For example, a purported `.env` file could contain command substitutions, shell functions, redirections, or direct commands in addition to variable assignments. Those statements would run with the permissions and environment of the process invoking the Skill. This exceeds the minimum privilege required by the declared functionality. The script only needs a small, documented set of LDR configuration values and does not need to execute general shell instructions from a credential file. ### Attack Path 1. An attacker obtains write access to `~/.config/local_deep_research/config/.env`, influences the inherited `LDR_CONFIG_DIR`, or causes it to reference an attacker-controlled directory. 2. The attacker places shell commands in the selected `.env` file. 3. The user or Agent invokes any action in `scripts/ldr-research.sh`. 4. Startup processing reaches `source "$LDR_ENV"`. 5. Bash executes the attacker-controlled commands before the requested research action begins. 6. The commands operate with the same filesystem, process, environment, and network permissions as the invoking Agent ...[truncated 814 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not use `source`, `.`, or `eval` to load `.env` files. 2. Prefer supplying credentials directly through the process environment or a dedicated secret manager. 3. If file-based configuration is required, implement a non-executing parser that: - Accepts only an explicit allowlist of supported keys. - Treats values as data rather than shell syntax. - Rejects command substitutions, function definitions, redirections, and malformed lines. - Validates each value according to its expected type and format. 4. Restrict accepted keys to documented variables such as `LDR_BASE_URL`, `LDR_SERVICE_USER`, `LDR_SERVICE_PASSWORD`, and supported default settings. 5. Before reading the file, verify that it: - Is a regular file rather than a symbolic link. - Is owned by the expected user. - Is not group- or world-writable. - Has restrictive permissions, preferably mode `0600`. 6. Avoid allowing an untrusted inherited `LDR_CONFIG_DIR` to select arbitrary files. If configurability is necessary, validate or explicitly approve the path. 7. Run the Skill in a constrained environment with only the filesystem and network access required to contact the LDR service. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ldr-research.sh:35
Finding
LDR Credentials Can Be Sent to an Untrusted, Plaintext, or Redirected Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ldr-research.sh`, lines 35–43 and 62–106 **Vulnerability Type**: Insufficient validation of a credential transmission destination **Risk Level**: Medium ### Vulnerable Code ```bash LDR_BASE_URL="${LDR_BASE_URL:-http://127.0.0.1:5000}" LDR_USERNAME="${LDR_SERVICE_USER:-${LDR_USERNAME:-}}" LDR_PASSWORD="${LDR_SERVICE_PASSWORD:-${LDR_PASSWORD:-}}" LDR_DEFAULT_MODE="${LDR_DEFAULT_MODE:-detailed}" LDR_DEFAULT_SEARCH_TOOL="${LDR_DEFAULT_SEARCH_TOOL:-auto}" LDR_DEFAULT_LANGUAGE="${LDR_DEFAULT_LANGUAGE:-}" # Login page URL (GET for form + CSRF; POST for submit). Adjust if LDR uses different path. LDR_LOGIN_URL="${LDR_LOGIN_URL:-${LDR_BASE_URL}/auth/login}" ``` ```bash login() { if [[ -z "$LDR_USERNAME" || -z "$LDR_PASSWORD" ]]; then return 0 fi log_info "Logging in to LDR (session + CSRF)..." local login_page login_page=$(curl -s -c "$COOKIE_JAR" -b "$COOKIE_JAR" -L --max-time "$HTTP_TIMEOUT" "$LDR_LOGIN_URL" 2>/dev/null) || true if [[ -z "$login_page" ]]; then log_error "Could not fetch login page at $LDR_LOGIN_URL" return 1 fi # Extract CSRF token from form (common: name="csrf_token" or "_csrf" or "csrf_token") CSRF_TOKEN=$(echo "$login_page" | sed -n 's/.*name="csrf_token"[^>]*value="\([^"]*\)".*/\1/p' | head -1) [[ -z "$CSRF_TOKEN" ]] && CSRF_TOKEN=$(echo "$login_page" | sed -n 's/.*name="_csrf"[^>]*value="\([^"]*\)".*/\1/p' | head -1) [[ -z "$CSRF_TOKEN" ]] && CSRF_TOKEN=$(echo "$login_page" | sed -n 's/.*value="\([^"]*\)"[^>]*name="csrf_token".*/\1/p' | head -1) if [[ -z "$CSRF_TOKEN" ]]; then log_warn "No CSRF token found on login page; POST may still work if LDR uses cookie-only CSRF" fi # POST login form (application/x-www-form-urlencoded) local post_data post_data="username=$(printf '%s' "$LDR_USERNAME" | jq -sRr @uri)&password=$(printf '%s' "$LDR_PASSWORD" | jq -sRr @uri)" [[ -n "$CSRF_TOKEN ...[truncated 4046 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Derive the login endpoint from the validated `LDR_BASE_URL` rather than accepting an unrestricted independent origin. 2. If `LDR_LOGIN_URL` must remain configurable, parse both URLs and require an exact match of scheme, hostname, and effective port. 3. Permit plaintext HTTP only for explicit loopback addresses such as `127.0.0.1`, `[::1]`, or a properly validated local Unix-socket deployment. 4. Require HTTPS for every non-loopback destination. 5. Disable redirects on credential-bearing requests, for example by removing `-L` or setting `--max-redirs 0`. 6. If redirects are operationally required, resolve and validate each destination before transmitting credentials and prohibit all cross-origin redirects. 7. Restrict Curl protocols with options such as `--proto '=https'` and `--proto-redir '=https'` for remote services. 8. Do not treat a redirect response as proof of successful authentication without validating its destination and confirming the resulting authenticated session. 9. Continue recommending a dedicated, minimally privileged LDR service account with a unique password. 10. Consider an explicit allowlist of approved LDR hosts in managed Agent deployments and restrict the Skill's network access to those hosts. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Ae1

High
Category
analysis-evasion
Content
end data to any endpoint other than the configured LDR service. You can review `scripts/ldr-research.sh` before use. For higher assurance, run it in an isolated
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
end data to any endpoint other than the configured LDR service. You can review `scripts/ldr-research.sh` before use. For higher assurance, run it in an isolated
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
end data to any endpoint other than the configured LDR service. You can review `scripts/ldr-research.sh` before use. For higher assurance, run it in an isolated
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
end data to any endpoint other than the configured LDR service. You can review `scripts/ldr-research.sh` before use. For higher assurance, run it in an isolated
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
end data to any endpoint other than the configured LDR service. You can review `scripts/ldr-research.sh` before use. For higher assurance, run it in an isolated
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Context Leakage

High
Category
Data Exfiltration
Content
### GET /research/api/status/{research_id}

Check the status of a research job. Send session cookie.

**Path Parameters:** `research_id` — research job UUID.
Confidence
85% confidence
Finding
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Context Leakage

High
Category
Data Exfiltration
Content
### GET /research/api/status/{research_id}

Check the status of a research job. Send session cookie.

**Path Parameters:** `research_id` — research job UUID.
Confidence
85% confidence
Finding
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Credential Access

High
Category
Privilege Escalation
Content
#   3. Reuses the session cookie (and CSRF token for POSTs) for API calls
# Credentials are for local LDR only; never transmitted elsewhere.
#
# Optional: ~/.config/local_deep_research/config/.env is sourced if present (verify its contents).
#

set -e
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
#   3. Reuses the session cookie (and CSRF token for POSTs) for API calls
# Credentials are for local LDR only; never transmitted elsewhere.
#
# Optional: ~/.config/local_deep_research/config/.env is sourced if present (verify its contents).
#

set -e
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
#   3. Reuses the session cookie (and CSRF token for POSTs) for API calls
# Credentials are for local LDR only; never transmitted elsewhere.
#
# Optional: ~/.config/local_deep_research/config/.env is sourced if present (verify its contents).
#

set -e
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
#   3. Reuses the session cookie (and CSRF token for POSTs) for API calls
# Credentials are for local LDR only; never transmitted elsewhere.
#
# Optional: ~/.config/local_deep_research/config/.env is sourced if present (verify its contents).
#

set -e
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
#   3. Reuses the session cookie (and CSRF token for POSTs) for API calls
# Credentials are for local LDR only; never transmitted elsewhere.
#
# Optional: ~/.config/local_deep_research/config/.env is sourced if present (verify its contents).
#

set -e
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
set -e

# Load LDR's local .env if present (secrets stay local)
LDR_ENV="${LDR_CONFIG_DIR:-$HOME/.config/local_deep_research/config}/.env"
if [[ -f "$LDR_ENV" ]]; then
    set -a
Confidence
92% confidence
Finding
The script sources a .env file from a user-controllable path using Bash source, which executes arbitrary shell code, not just key=value assignments. If an attacker can modify that file or influence LDR_CONFIG_DIR, they can achieve arbitrary command execution in the context of the script and access credentials or alter network destinations.

Credential Access

High
Category
Privilege Escalation
Content
set -e

# Load LDR's local .env if present (secrets stay local)
LDR_ENV="${LDR_CONFIG_DIR:-$HOME/.config/local_deep_research/config}/.env"
if [[ -f "$LDR_ENV" ]]; then
    set -a
    # shellcheck source=/dev/null
Confidence
96% confidence
Finding
The conditional around source causes any existing .env at the resolved path to be executed. Because this is an execution sink for local file contents, it creates a strong local code-execution and credential-compromise risk if the file path or file contents are attacker-controlled.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The README advertises very broad trigger phrases such as "research this topic" and "investigate [topic]", which are common natural-language requests and can cause the skill to activate unintentionally. In an agent environment, accidental invocation can expand the skill’s network and shell use, potentially sending user queries to the local research service without clear intent.

Session Persistence

Medium
Category
Rogue Agent
Content
## Credentials (local-only)

LDR uses **session-cookie authentication with CSRF protection** (not HTTP Basic Auth). The script performs a proper login flow: fetches the login page for a session cookie and CSRF token, then POSTs the login form. Your username and password are used **only** to create that session with **your local** LDR instance (and for LDR’s per-user encrypted results).

- **They are not transmitted** to any third party or to ClawHub/GitHub — only to your own LDR instance (e.g. on localhost).
- **Do not** put credentials in the skill config file or commit them to git.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger list includes broad phrases such as "research this topic", "quick summary on [topic]", and "detailed report on [topic]", which are common user requests and may cause unintended activation beyond this specific skill. The description also says the skill is used for "any research requiring exhaustive web search," which lacks clear exclusion boundaries or negative examples.

Session Persistence

Medium
Category
Rogue Agent
Content
### Credentials (local-only, never transmitted)

LDR uses **session-cookie auth with CSRF protection** (not HTTP Basic Auth). The skill script performs a proper login flow: GET login page → obtain session cookie and CSRF token → POST credentials + CSRF → reuse session cookie (and CSRF for POSTs) for all API calls. Username and password are used **only** to create a session with your **local** LDR instance; they are never sent to ClawHub, GitHub, or any other server.

**Do not** put credentials in skill config or committed files. Use **environment variables or a local `.env` file** only (e.g. `LDR_SERVICE_USER`, `LDR_SERVICE_PASSWORD`, or `LDR_USERNAME`/`LDR_PASSWORD`). Optional: LDR’s `~/.config/local_deep_research/config/.env` is sourced by the script if present. Use a dedicated LDR user (e.g. `openclaw_service`) for this skill.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
[[ -n "$CSRF_TOKEN" ]] && post_data="csrf_token=$(printf '%s' "$CSRF_TOKEN" | jq -sRr @uri)&$post_data"

    local http_code
    http_code=$(curl -s -o /dev/null -w "%{http_code}" -c "$COOKIE_JAR" -b "$COOKIE_JAR" -L --max-time "$HTTP_TIMEOUT" \
        -X POST \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -d "$post_data" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
while [[ $attempt -lt $RETRY_COUNT ]]; do
        local response http_code
        if [[ "$method" == "GET" ]]; then
            response=$(curl -s -w "\n%{http_code}" -b "$COOKIE_JAR" --max-time "$HTTP_TIMEOUT" "$url" 2>/dev/null)
        else
            if [[ -n "$CSRF_TOKEN" ]]; then
                response=$(curl -s -w "\n%{http_code}" -b "$COOKIE_JAR" -H "X-CSRFToken: $CSRF_TOKEN" --max-time "$HTTP_TIMEOUT" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.