Back to skill

Security audit

Local Ai Search

Security checks for vulnerabilities and agentic risk

Overview

This is a real local document-search skill, but its default service exposure, unrestricted upload endpoint, and scheduled-sync implementation create privacy and persistence risks that need review before installation.

Install only if you are comfortable with a Khoj service indexing selected local documents, storing sync state under ~/.khoj, and sending query content to configured cloud LLM providers. Before use, bind Khoj to 127.0.0.1, avoid anonymous mode on reachable networks, keep KHOJ_URL on a trusted loopback or authenticated HTTPS endpoint, review files before indexing or syncing, and avoid enabling scheduled sync until the cron construction is fixed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/schedule_sync.sh:36
Finding

Persistent Command Execution Through Unsafe Cron Entry Construction

Content
View full analysis
> \"$LOG_FILE\" 2>&1" # Check whether a task already exists if crontab -l 2>/dev/null | grep -q "$SYNC_SCRIPT"; then echo -e "${YELLOW}Scheduled task already exists; updating...${NC}" crontab -l 2>/dev/null | grep -v "$SYNC_SCRIPT" | crontab - fi # Add the new task (crontab -l 2>/dev/null; echo "$cron_job") | crontab - } ``` The interval is accepted without validation: ```bash INTERVAL=1 while [[ $# -gt 0 ]]; do case $1 in --interval) INTERVAL="$2" shift 2 ;; ``` ### Technical Analysis The script interpolates the user-controlled `interval` and `directory` values directly into a crontab command. Cron executes task commands through a shell, so quoting the directory with double quotes does not prevent command substitution, variable expansion, or quote termination when the task later runs. The `interval` parameter can also contain spaces or newline characters because it is not restricted to an integer. Such input can alter the cron schedule or introduce an additional cron entry. The directory existence check does not eliminate the issue. Unix paths can contain spaces, quotes, dollar signs, parentheses, and other shell-significant characters. An attacker can create a directory whose literal name contains a command-substitution expression and then register that directory. Sched ...[truncated 1488 chars]
Remediation
View remediation
24 )); then echo "Invalid interval" >&2 exit 1 fi ``` 2. Reject directory values containing newlines, carriage returns, NUL-equivalent input, or other characters that cannot be represented safely in a crontab entry. 3. Do not embed an arbitrary directory directly into a shell command. Store the canonical directory in a user-owned configuration file with mode `0600`, and install a fixed cron command that reads the configuration without evaluating it as shell syntax. 4. If direct insertion is unavoidable, use a rigorously tested shell-quoting routine rather than double quotes alone. 5. Resolve and validate the directory with `realpath`, and ensure the cron wrapper treats the resulting value strictly as data. 6. Add a unique marker to the managed cron entry and modify only that exact entry rather than removing every line that happens to contain the script path. 7. Display the complete proposed cron entry and require explicit confirmation before installation. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
config.yaml:50
Finding

Anonymous Khoj Service Configuration Can Expose Private Indexed Documents to the Network

Content
View full analysis
/tmp/khoj.log 2>&1 & ``` The same anonymous startup mode is recommended in the Skill instructions: ```bash export USE_EMBEDDED_DB="true" khoj --anonymous-mode ``` ### Technical Analysis The declared functionality is local document search, for which listening only on the loopback interface is sufficient. Binding to `0.0.0.0` makes the service eligible to receive connections through every active interface, including local networks, VPN interfaces, container bridges, and potentially public interfaces. At the same time, the recommended startup path enables Khoj's anonymous mode. If Khoj loads the supplied host configuration or otherwise binds beyond loopback, the combination can expose content, search, chat, and indexing endpoints without user authentication. Even where the specific Khoj release defaults to loopback, the project configuration encourages an unsafe deployment state and does not explicitly force a loopback bind in either startup implementation. ### Attack Path 1. A user copies or activates the supplied configuration and starts Khoj using the documented anonymous-mode command. 2. The service listens on port `42110` on one or more non-loopback interfaces. 3. An attacker on a reachable network discovers the open port. 4. The attacker accesses unauthenticated Khoj endpoints. 5. Depending on the endpoint behavior and Khoj version, the attacker searches indexed content, retrieves metadata or document ...[truncated 642 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
khoj_cli.py:21
Finding

Environment-Controlled Plaintext Endpoint Can Receive Documents, Queries, and Bearer Tokens

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:4
Finding

Open-Ended Dependency Constraints Permit Installation of Unreviewed Future Releases

Content
View full analysis
=0.1.0 markitdown>=0.1.0 # Office document support openpyxl>=3.1.0 python-pptx>=0.6.21 python-docx>=1.1.0 # CLI click>=8.0.0 requests>=2.28.0 ``` The documentation also instructs users to install packages without reviewed versions: ```bash pip install khoj "markitdown[xlsx,pptx]" pip install khoj "markitdown[xlsx,pptx]" requests ``` ### Technical Analysis Every dependency has only a lower bound or no version constraint. Package resolution may therefore install any future release published under these package names. No lockfile or integrity hashes are supplied. These dependencies are security-sensitive: Khoj runs a network service, MarkItDown and the Office libraries parse complex user documents, and Requests transmits document contents and credentials. A compromised upstream release, malicious maintainer update, or unexpectedly incompatible version would execute within the user's environment with the same permissions as the Skill. This finding does not establish that any currently named package is malicious. It identifies a supply-chain control weakness that allows the installed code to change after the Skill itself has been reviewed. ### Attack Path 1. A dependency account, publishing workflow, or package release is compromised, or a future release introduces malicious behavior. 2. A user follows the supplied installation instructions or rebuilds the environment. 3. The package resolver selects the newest release satisfying the open-ended constraint. 4. Installation hooks, imported module code, parser code, or service code executes under the user's account. 5. The compromised dependency gains access to documents processed by the Skill, environment variables containing API keys, and network connectivity. ### Impact Assessment A malicious depe ...[truncated 374 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (85)

Tainted flow: 'KHOJ_URL' from os.environ.get (line 21, credential/environment) → requests.get (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 · khoj_cli.py (reported line 186)May include surrounding context.

python
# 获取统计信息
    try:
        response = requests.get(f"{KHOJ_URL}/api/content/stats", timeout=5)
        if response.status_code == 200:
            stats = response.json()
            click.echo(f"文档数: {stats.get('document_count', 'N/A')}")

Tainted flow: 'KHOJ_URL' from os.environ.get (line 19, credential/environment) → requests.get (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/query.py (reported line 30)May include surrounding context.

python
headers["Authorization"] = f"Bearer {KHOJ_API_KEY}"
    
    try:
        response = requests.get(
            f"{KHOJ_URL}/api/search",
            params={"q": query, "n": top_k},
            headers=headers,

Tainted flow: 'KHOJ_URL' from os.environ.get (line 19, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The chat path sends user prompts over HTTP to a configurable endpoint from KHOJ_URL, so an attacker who can influence that environment variable can redirect sensitive local-search queries to an unintended server. This is more concerning in the context of a skill advertised as local file search, because users may reasonably expect queries to stay local and may not realize the tool can transmit them to another host.

Content

Scanner excerpt · scripts/query.py (reported line 54)May include surrounding context.

python
headers["Authorization"] = f"Bearer {KHOJ_API_KEY}"
    
    try:
        response = requests.post(
            f"{KHOJ_URL}/api/chat",
            json={"q": query},
            headers=headers,

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill’s real behavior includes indexing, synchronization, state persistence, API calls, OCR/conversion pipelines, and broader file-type handling than declared. This gap matters because users expecting a simple local search tool may unknowingly authorize mass ingestion, persistent storage, and broader document processing than intended.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · khoj_cli.py (reported line 126)May include surrounding context.

python
click.echo("✓ Khoj 服务已在运行")
        return
    
    env = os.environ.copy()
    env["USE_EMBEDDED_DB"] = "true"
    
    cmd = ["khoj"]

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

Host process termination via pkill is not justified by a narrow local-search role and can impact unrelated processes. In the context of an agent skill, this kind of system-control behavior is especially risky because it violates least privilege and user expectations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill executes external programs and shell scripts for document conversion, sync, and scheduling, which broadens privileges and behavior well beyond search. In agent contexts this is dangerous because it introduces supply-chain risk, persistence mechanisms, and host modification capabilities under a deceptively simple interface.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This script performs bulk document conversion and writes Markdown outputs to disk, which is materially different from the declared skill purpose of natural-language local file search. In an agent context, extra file-processing capabilities increase the attack surface and could enable unintended mass extraction or staging of local document contents for later indexing or exfiltration.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code recursively traverses an input directory, converts supported documents, and writes extracted text to a parallel output tree. For a search skill, this is a high-risk overbroad capability because it can duplicate large volumes of sensitive local content into new Markdown files, expanding exposure and persistence without clear necessity.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script modifies the user's crontab to establish recurring execution of sync.py, which is a persistence mechanism. Persistence is security-sensitive because it causes code to run automatically in the future and can be abused to repeatedly access local files or continue operating after the user forgets it was enabled.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/schedule_sync.sh (reported line 53)May include surrounding context.

sh
irectory="$1"
    local interval="$2"
    
    # 验证目录
    if [ ! -d "$directory" ]; then
        echo -e "${RED}错误: 目录不存在 - $directory${NC}"
        exit 1
    fi
    
    # 创建日志目录
    mkdir -p "$LOG_DIR"
    
    # 创建 cron 任务
    local cron_job="0 */$interval * * * $SYNC_SCRIPT \"$directory\" >> \"$LOG_FILE\" 2>&1"
    
    # 检查是否已存在
    if crontab -l 2>/dev/null | grep -q "$SYNC_SCRIPT"; then
        echo -e "${YELLOW}定时任务已存在,正在更新...${NC}"
        # 移除旧任务
        crontab -l 2>/dev/null | grep -v "$SYNC_SCRIPT" | crontab -
    fi
    
    # 添加新任务
    (crontab -l 2>/dev/null; echo "$cron_job") | crontab -
    
    echo -e "${GREEN}✓ 已设置定时同步${NC}"
    echo "  目录: $directory"
    echo "  间隔: 每 $interval 小时"
    echo "  日志: $LOG_FILE"
    echo ""
    echo "查看日志: tail -f $LOG_FILE"
}

disable_cron() {
    if crontab -l 2>/dev/null | grep -q "$SYNC_SC

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script is presented as a local file search capability, but it reads local documents and uploads their contents to a Khoj HTTP endpoint for indexing. Even if the default target is localhost, the endpoint is configurable via environment variable, so sensitive local data can be sent to a different service without clear disclosure, making this a significant privacy and data-exposure issue in the skill context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language instructions, triggers, and usage guidance are entirely in Chinese, and the trigger section assumes Chinese-language invocation phrases. There is no indication that this language constraint is optional, user-selected, or required for a region-specific purpose.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger conditions are very broad and are phrased as mandatory invocation rules for any request involving local/computer/folder search. In an agent setting, this can cause over-activation on common user requests and route sensitive local-file tasks to a skill that may index or query content through additional tooling, increasing the chance of unintended data exposure or unsafe execution paths.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

The documentation includes configuration for a third-party API endpoint, confirming that the skill can send data to an external service. In the context of a local document search skill, external transmission is more dangerous because users may assume their local files remain on-device; without strict disclosure and controls, sensitive document text and queries could be exposed to a remote provider.

Content

Scanner excerpt · README.md (reported line 30)May include surrounding context.

export OPENAI_API_KEY="your-api-key"

或 DeepSeek

export OPENAI_API_KEY="your-api-key" export OPENAI_BASE_URL="https://api.deepseek.com/v1"

text

### 使用

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly advertises cloud LLM API use for local document search but does not warn that document contents, extracted text, metadata, or user queries may be transmitted to external services. Because the skill is designed for large-scale local document indexing, this omission can mislead users into exposing sensitive local data under the assumption the workflow is fully local.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 102)May include surrounding context.

md
brew install tesseract tesseract-lang

# Ubuntu 安装 Tesseract
sudo apt install tesseract-ocr tesseract-ocr-chi-sim

# .doc 文件支持(可选)
# macOS

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 108)May include surrounding context.

macOS

brew install libreoffice

Ubuntu

sudo apt install libreoffice

text

## 文件结构

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill advertises substantial capabilities—shell execution, filesystem access, environment variable use, and network communication—but does not declare any tool scope or permissions boundary. That makes the agent’s effective authority opaque and increases the risk of unintended file access, service manipulation, or data exposure when the skill is invoked.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The trigger section defines activation phrases only in Chinese and presents them as the required invocation conditions. For a generally applicable local-search skill, this imposes a language-specific interaction model without user opt-in or a documented reason for the locale limitation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.