Back to skill

Security audit

Exa Search (Rust)

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed Exa web-search integration whose network and API-key use match its stated purpose, with some privacy and prompt-injection cautions for users.

Install only if you are comfortable sending your search terms and requested URLs to Exa using your EXA_API_KEY. Do not use it for secrets, internal-only URLs, or regulated data unless that third-party data sharing is approved, and treat fetched page text as untrusted web content rather than instructions for the agent to follow.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T01 · Skill Instruction Hijacking

Warning
Location
src/protocol.rs:81
Finding
Untrusted Web Content Is Presented as Ready-to-Use Agent Output## Vulnerability Details **File Location**: `src/protocol.rs:81-91`; related unsafe usage instructions at `SKILL.md:140` and `SKILL.md:178` **Vulnerability Type**: Indirect prompt injection through untrusted search and page content **Risk Level**: Medium **Vulnerable code (`src/protocol.rs:81-91`):** ```rust /// Build the markdown-formatted string from results. pub fn format_results(results: &[ExaResult]) -> String { results .iter() .map(|r| { let title = r.title.as_deref().unwrap_or("Untitled"); let url = &r.url; let body = r.summary.as_deref().or(r.text.as_deref()).unwrap_or(""); format!("## [{title}]({url})\n\n{body}\n\n---") }) .collect::<Vec<_>>() .join("\n\n") } ``` **Related instructions (`SKILL.md:140` and `SKILL.md:178`):** ```markdown The `formatted` field is ready-to-use markdown — you can send it directly to the user. ``` ### Technical Analysis The `format_results` function places titles, URLs, summaries, and extracted page text returned by Exa directly into Markdown. These values originate from external web pages and must therefore be treated as attacker-controlled content. No trust boundary, escaping, sanitization, or warning distinguishes retrieved page content from instructions intended for the Agent. The Skill documentation compounds this problem by explicitly stating that the generated Markdown can be sent directly to the user. In an Agent workflow, retrieved text may be placed back into the model context before the final response is generated. A malicious page can embed instructions such as requests to ignore the current task, reveal confidential context, invoke another tool, or follow an attacker-controlled link. Markdown construction also accepts the remote title and URL without validation. Although this does not itself execute code in the Rust process, it can create misle ...[truncated 1552 chars]
Remediation
## Remediation Suggestions 1. Remove the instruction that the `formatted` field may be sent directly to the user. 2. Clearly label all search results and fetched page contents as untrusted external data. 3. In `SKILL.md`, instruct the Agent never to follow commands, policies, credential requests, or tool-use directives found in retrieved content. 4. Prefer structured JSON fields over preformatted Markdown so the caller can apply its own trust and presentation policy. 5. If Markdown output remains supported, validate URL schemes, escape attacker-controlled titles, and delimit page text in a clearly marked quotation or data block. 6. Require the Agent to extract factual information and produce a fresh summary rather than forwarding remote text verbatim. 7. Apply output-size limits per result and consider filtering common prompt-injection phrases as defense in depth. Such filtering must not replace explicit trust-boundary enforcement.

T08 · Insecure Dependencies

Note
Location
Cargo.toml:16
Finding
Installation Does Not Enforce a Reproducible Locked Dependency Graph## Vulnerability Details **File Location**: `Cargo.toml:16-21`; dependency resolution is triggered by `install.sh:11` **Vulnerability Type**: Unlocked third-party build dependencies **Risk Level**: Low **Dependency declarations (`Cargo.toml:16-21`):** ```toml [dependencies] reqwest = { version = "0.12", features = ["json"] } tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" anyhow = "1" ``` **Build command (`install.sh:9-13`):** ```bash echo "🦀 Building exa-search binary..." cd "$SKILL_DIR" cargo build --release mkdir -p "$SKILL_DIR/bin" cp target/release/exa-search "$SKILL_DIR/bin/exa-search" ``` ### Technical Analysis The audited project structure does not contain a `Cargo.lock` file, while `Cargo.toml` specifies semver-compatible dependency ranges. The installer runs `cargo build --release` without the `--locked` option. Installation can therefore resolve dependency and transitive-dependency versions available at build time instead of enforcing a dependency graph reviewed with the Skill source. No malicious or typosquatted package was identified in the declared direct dependencies. This finding concerns supply-chain hardening rather than evidence that the current dependencies are malicious. Nevertheless, compilation and installation occur inside the user’s environment, and dependency changes can alter the effective binary after the Skill source has been reviewed. ### Attack Path 1. A direct or transitive dependency publishes a compromised version that satisfies the declared semver constraints, or its registry account or upstream source is compromised. 2. A user installs the Skill after that version becomes available. 3. Because no reviewed lockfile is enforced, Cargo resolves the affected dependency version. 4. `cargo build --release` compiles the resolved code in the user’s environment. 5. The installer c ...[truncated 664 chars]
Remediation
## Remediation Suggestions 1. Generate and commit a reviewed `Cargo.lock` file for this executable project. 2. Change the installer to use: ```bash cargo build --release --locked ``` 3. Review lockfile changes as part of every dependency update. 4. Run tools such as `cargo audit` and `cargo deny` in continuous integration to identify known vulnerabilities, unapproved sources, and problematic licenses. 5. Pin the Rust toolchain with a `rust-toolchain.toml` file where reproducible builds are required. 6. Consider generating an SBOM and verifying package checksums or build provenance for published releases.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (16)

Credential Access

High
Category
Privilege Escalation
Content
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

---
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
Then add your API key to `~/.openclaw/workspace/.env`:

```bash
echo "EXA_API_KEY=your_key_here" >> ~/.openclaw/workspace/.env
```

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

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README instructs users to send queries, URLs, and fetched page contents to the third-party Exa service but does not clearly warn that these inputs leave the local environment. In an agent skill context, users may pass sensitive prompts, internal URLs, or proprietary research terms through the tool, creating an avoidable privacy and data-sharing risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill invokes a native binary that performs outbound web requests, but the manifest does not declare any explicit tool scope such as permissions or allowed-tools. That weakens least-privilege controls and makes the network capability less visible to reviewers and runtime policy systems.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill is designed to send search queries, URLs, and fetched page contents to an external third-party service, but the documentation does not clearly warn about that privacy boundary. Users may unknowingly transmit sensitive prompts, internal URLs, or proprietary targets to Exa.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The examples tell operators to extract an API key from a local .env file and place it into shell variables without any caution about secret handling. This can lead to unsafe reuse patterns, accidental logging, shell history exposure, or copying credentials into broader workflows.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "🦀 Building exa-search binary..."
cd "$SKILL_DIR"
cargo build --release
mkdir -p "$SKILL_DIR/bin"
cp target/release/exa-search "$SKILL_DIR/bin/exa-search"
echo "✅ Binary built → $SKILL_DIR/bin/exa-search"
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.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The search, find_similar, and get_contents methods serialize request options and send them to the remote Exa API, which may include user-provided or system-derived data. In this file there is no confirmation prompt, user-facing log/print, or comment/docstring warning that data is transmitted off-system.

Missing User Warnings

Low
Confidence
78% confidence
Finding
This Rust code accesses the sensitive `EXA_API_KEY` environment variable, which falls under the code-file warning criteria for credential access. Although the variable is validated and not printed, there is no confirmation prompt, user-facing notice, or explanatory comment/docstring indicating that the skill reads credentials from the environment.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The code constructs an HTTP client and dispatches search/content actions that send input data to an external service, but this file provides no user-facing print/log message, confirmation, or explanatory documentation about transmitting queries, URLs, or related parameters. Network transmission of user-provided data is explicitly in scope for missing-warning checks on code files.

Static analysis

No suspicious patterns detected.