T09 · Insecure Skill Coding Practices
- Location
scripts/ldr-research.sh:24- Finding
Arbitrary Shell Execution Through Sourced Environment File
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/ldr-research.sh:24Arbitrary Shell Execution Through Sourced Environment File
scripts/ldr-research.sh:35LDR Credentials Can Be Sent to an Untrusted, Plaintext, or Redirected Endpoint
Referenced artifact was not completely inspected
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
Referenced artifact was not completely inspected
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
Referenced artifact was not completely inspected
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
Referenced artifact was not completely inspected
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
Referenced artifact was not completely inspected
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
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.
### GET /research/api/status/{research_id}
Check the status of a research job. Send session cookie.
**Path Parameters:** `research_id` — research job UUID.
Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.
### GET /research/api/status/{research_id}
Check the status of a research job. Send session cookie.
**Path Parameters:** `research_id` — research job UUID.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 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
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.
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
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.
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
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.
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.
## 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.
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.
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.
### 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.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
[[ -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" \
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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" \