Back to skill

Security audit

anythingllm-rag

Security checks for vulnerabilities and agentic risk

Overview

This AnythingLLM document-search skill is mostly purpose-aligned, but it ships an embedded API key and contains a reachable shell-injection flaw that can run local commands.

Review before installing. Use only with a trusted local AnythingLLM instance, remove and rotate the embedded API key, require an explicit user-provided token, replace eval-based curl construction, and avoid uploading sensitive documents until the destination URL, transport security, and storage behavior are clear.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/anythingllm.sh:21
Finding
Arbitrary Command Execution Through Shell eval<![CDATA[ ## Vulnerability Details **File Location**: `scripts/anythingllm.sh`, lines 21–35 and 79–94 **Vulnerability Type**: Shell command injection caused by unsafe command-string construction and `eval` **Risk Level**: Critical ### Vulnerable Code ```bash api_call() { local method="$1" local endpoint="$2" local data="$3" local curl_cmd="curl -s -w '\n%{http_code}' -X ${method} \ -H 'Authorization: Bearer ${ANYTHINGLLM_API_KEY}' \ -H 'Content-Type: application/json' \ '${ANYTHINGLLM_URL}/api${endpoint}'" if [ -n "$data" ]; then curl_cmd="${curl_cmd} -d '${data}'" fi local response=$(eval "$curl_cmd") local http_code=$(echo "$response" | tail -n1) local body=$(echo "$response" | sed '$d') ``` The attacker-controlled data can originate from the raw-text upload function: ```bash upload_text() { local text="$1" local title="$2" local workspace="${3:-$DEFAULT_WORKSPACE}" local payload=$(cat <<EOF { "textContent": "$(echo "$text" | sed 's/"/\\"/g' | tr '\n' ' ')", "metadata": { "title": "${title}" }, "addToWorkspaces": "${workspace}" } EOF ) api_call "POST" "/v1/document/raw-text" "$payload" } ``` ### Technical Analysis `api_call` constructs an entire shell command as a string and then reparses it with `eval`. The JSON body is inserted into a single-quoted `-d` argument: ```bash curl_cmd="${curl_cmd} -d '${data}'" ``` The `upload_text` function only escapes double quotation marks in `text`; it does not escape shell-significant single quotation marks. The `title` and `workspace` values are not safely JSON-encoded or shell-escaped either. Consequently, an apostrophe in supplied content can terminate the intended single-quoted argument. Subsequent shell syntax is then interpreted by `eval`. Environment-controlled values such as `ANYTHINGLLM_URL` and `ANYTHINGLLM_API_KEY` are also interpolated into the evaluated command string ...[truncated 1794 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `eval` and never build a shell command as a string. 2. Call `curl` directly with individually quoted arguments or a Bash array: ```bash local curl_args=( -s -w $'\n%{http_code}' -X "$method" -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" -H "Content-Type: application/json" ) if [[ -n "$data" ]]; then curl_args+=(-d "$data") fi response="$(curl "${curl_args[@]}" "${ANYTHINGLLM_URL}/api${endpoint}")" ``` 3. Generate JSON with a proper serializer such as `jq`, rather than escaping selected characters with `sed`: ```bash payload="$(jq -n \ --arg text "$text" \ --arg title "$title" \ --arg workspace "$workspace" \ '{textContent: $text, metadata: {title: $title}, addToWorkspaces: $workspace}')" ``` 4. Validate the API URL and restrict it to expected schemes and hosts. 5. Validate workspace identifiers against the format accepted by AnythingLLM. 6. Add regression tests containing apostrophes, quotation marks, command substitutions, semicolons, newlines, and shell metacharacters. 7. Run the skill under a least-privileged account to reduce impact if another command-injection defect is introduced. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/anythingllm.sh:13
Finding
Hard-Coded AnythingLLM Bearer Credential<![CDATA[ ## Vulnerability Details **File Location**: `scripts/anythingllm.sh`, line 13 **Vulnerability Type**: Hard-coded API secret in distributable source code **Risk Level**: High ### Vulnerable Code ```bash ANYTHINGLLM_API_KEY="${ANYTHINGLLM_API_KEY:-JYF2P4K-SQ6MKA3-NGW734W-6CVY672}" ``` ### Technical Analysis The script includes a reusable AnythingLLM API key as its fallback configuration. Anyone who can read or download the skill package can recover this credential without accessing a protected secret store. The script silently uses the embedded key whenever `ANYTHINGLLM_API_KEY` is unset. It then sends that credential as a bearer token to multiple API endpoints. Because bearer tokens authorize their holder directly, possession of the value may be sufficient to exercise all permissions granted to the associated AnythingLLM account or token. An environment-variable override does not protect the embedded fallback: the credential remains present in source history, distributed archives, caches, and existing installations. ### Attack Path 1. An attacker obtains a copy of the public or otherwise distributed skill package. 2. The attacker reads `scripts/anythingllm.sh` and extracts the fallback bearer token. 3. The attacker identifies or reaches the corresponding AnythingLLM deployment. 4. The attacker sends API requests with the recovered value in the `Authorization: Bearer` header. 5. If the token remains valid, the attacker gains the token's effective AnythingLLM permissions. ### Impact Assessment The precise scope depends on the server-side permissions assigned to the token. Based on the operations implemented by this client, possible impact includes: - Querying private RAG workspaces. - Reading workspace or document metadata. - Listing available workspaces. - Uploading attacker-controlled documents or raw text. - Poisoning workspace retrieval results. - Accessing any additional API operations authorized for the token. The credential should be tr ...[truncated 181 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Immediately revoke and rotate the exposed API key. 2. Remove the fallback credential from the repository and all distributed packages. 3. Require explicit secret configuration and terminate safely if it is absent: ```bash : "${ANYTHINGLLM_API_KEY:?ANYTHINGLLM_API_KEY must be configured securely}" ``` 4. Store the replacement credential in an operating-system secret store, deployment secret manager, or protected environment configuration. 5. Ensure secret files are excluded from version control and have restrictive filesystem permissions. 6. Review repository history, build artifacts, logs, caches, and releases for additional copies. 7. Audit AnythingLLM access logs for unauthorized use of the exposed token. 8. Assign the replacement token only the minimum API permissions needed by this skill and use separate credentials for separate environments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/anythingllm.sh:12
Finding
Sensitive API Traffic Permitted Over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/anythingllm.sh`, lines 12 and 53–57 **Vulnerability Type**: Cleartext transmission of bearer credentials and private document data **Risk Level**: Medium ### Vulnerable Code ```bash ANYTHINGLLM_URL="${ANYTHINGLLM_URL:-http://localhost:3001}" ``` The configured URL is used while sending the bearer credential and user-supplied query content: ```bash curl -s -X POST \ -H "Authorization: Bearer ${ANYTHINGLLM_API_KEY}" \ -H "Content-Type: application/json" \ "${ANYTHINGLLM_URL}/api/v1/workspace/${workspace}/chat" \ -d "$payload" ``` The same URL is also used for document uploads and other authenticated API calls: ```bash curl -s -X POST \ -H "Authorization: Bearer ${ANYTHINGLLM_API_KEY}" \ -F "file=@${file}" \ -F "addToWorkspaces=${workspace}" \ "${ANYTHINGLLM_URL}/api/v1/document/upload" ``` ### Technical Analysis The default endpoint uses plaintext HTTP. The loopback default reduces exposure when the server is genuinely bound to the same trusted host, but the script permits `ANYTHINGLLM_URL` to be replaced with an arbitrary remote HTTP URL without warning or rejection. Authenticated requests transmit a bearer credential as well as potentially sensitive queries, raw text, documents, workspace identifiers, and API responses. Plain HTTP provides no transport confidentiality or server authentication. Traffic crossing an untrusted network can therefore be observed or altered by a suitably positioned attacker. Because bearer credentials can generally be replayed, interception may lead to continuing unauthorized API access rather than disclosure of only a single request. ### Attack Path 1. The skill is configured with a remote `http://` AnythingLLM endpoint, or local traffic is redirected through an untrusted network path. 2. A user invokes a query, upload, listing, workspace, or health operation. 3. The script transmits the bearer token and request data without TLS. ...[truncated 929 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require HTTPS for every non-loopback endpoint. 2. Parse and validate `ANYTHINGLLM_URL` before making requests; reject remote URLs using `http://`. 3. If plaintext HTTP is retained for a local deployment, permit it only for explicitly recognized loopback addresses such as `localhost`, `127.0.0.1`, or `::1`. 4. Use a properly configured certificate issued by a trusted internal or public certificate authority. 5. Do not disable `curl` certificate verification. 6. Protect bearer tokens with short lifetimes, restricted scopes, and regular rotation. 7. Document that reverse proxies and remote AnythingLLM deployments must terminate TLS before receiving skill traffic. 8. Consider certificate pinning or a private CA for high-sensitivity internal deployments. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented purpose is limited to querying and uploading documents, but the behavior reportedly also includes workspace enumeration, document listing, health/auth checks, and a hardcoded default API key. That mismatch is dangerous because it expands access beyond user-expected actions and can facilitate reconnaissance, unauthorized data discovery, or credential misuse—especially severe if a default key is embedded.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill invokes shell-based scripts but does not declare any explicit tool scope or allowed-tools boundary. This creates an authorization and review gap: operators and downstream agents cannot clearly tell that the skill can execute shell commands that access local files and networked services, increasing the chance of unintended command execution or data access.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill supports uploading files and raw text but does not clearly warn that private/local content will be transmitted to the AnythingLLM service. In a document-oriented skill, this context makes the omission more dangerous because users are likely to provide sensitive PDFs, notes, or proprietary text under the assumption they remain purely local.

External Transmission

Medium
Category
Data Exfiltration
Content
local endpoint="$2"
    local data="$3"
    
    local curl_cmd="curl -s -w '\n%{http_code}' -X ${method} \
        -H 'Authorization: Bearer ${ANYTHINGLLM_API_KEY}' \
        -H 'Content-Type: application/json' \
        '${ANYTHINGLLM_URL}/api${endpoint}'"
Confidence
98% confidence
Finding
The generic `api_call` function constructs a shell command string containing attacker-influenced values and executes it with `eval`. Because `endpoint` and `data` can include quotes or shell metacharacters, this creates a command injection path in addition to transmitting data externally with authorization headers.

External Transmission

Medium
Category
Data Exfiltration
Content
EOF
)
    
    curl -s -X POST \
        -H "Authorization: Bearer ${ANYTHINGLLM_API_KEY}" \
        -H "Content-Type: application/json" \
        "${ANYTHINGLLM_URL}/api/v1/workspace/${workspace}/chat" \
Confidence
85% confidence
Finding
This call sends user questions to the AnythingLLM chat endpoint together with an authorization token, which is an external transmission of potentially sensitive content. In the context of a private-document RAG skill this behavior is expected, but it still poses confidentiality risk because prompts may contain private or regulated data and the service endpoint is configurable.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill sends user-provided questions, uploaded files, and raw text to an HTTP API endpoint without any explicit disclosure or consent prompt. Even if the service is local by default, this still transmits potentially sensitive document contents and queries to another service boundary, which creates privacy and data handling risk.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The script exposes `workspaces` and `health` commands that go beyond the declared document query/upload purpose and allow environment discovery. While not directly destructive, these functions expand the skill's capability to enumerate internal resources and confirm authenticated access, which can aid lateral misuse or reconnaissance.

Missing User Warnings

Low
Confidence
97% confidence
Finding
The script contains a default hardcoded API key and uses it automatically for authentication without disclosure. Embedding credentials in a distributable skill risks secret leakage, unauthorized access reuse, and accidental exposure if the script is shared, logged, or committed publicly.

Static analysis

No suspicious patterns detected.