Back to skill

Security audit

Orange Wallet

Security checks for vulnerabilities and agentic risk

Overview

This is a real Lightning wallet skill with disclosed behavior, but it needs Review because it handles funds while storing the wallet seed plainly and sending payment events to arbitrary webhooks without strong safeguards.

Review before installing or using with real funds. Use only small test balances, protect and back up the seed file, set restrictive permissions on the storage directory, avoid HTTP webhooks, send webhook events only to trusted endpoints, and prefer safer Rust/protoc installation methods over piping remote scripts into a shell.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (5)

T03 · Remote Payload Retrieval and Execution

Error
Location
README.md:18
Finding

Unverified Rust Installer Is Downloaded and Executed Directly

Content
View full analysis
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:17
Finding

Skill Setup Instructions Execute an Unverified Remote Installer

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/config.rs:138
Finding

Wallet Recovery Mnemonic Is Written Without Enforced Owner-Only Permissions

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/main.rs:342
Finding

Webhook Configuration Allows Bearer Tokens and Payment Metadata over Plaintext HTTP

Content
View full analysis
)> = webhooks .iter() .map(|w| match w.split_once('|') { Some((url, token)) => (url.to_string(), Some(token.trim().to_string())), None => (w.clone(), None), }) .collect(); ``` ```rust for (url, token) in &hooks { let client = client.clone(); let url = url.clone(); let body = value.clone(); let token = token.clone(); tokio::spawn(async move { let max_retries = 3u32; for attempt in 0..=max_retries { let mut req = client.post(&url).json(&body); if let Some(ref t) = token { req = req.bearer_auth(t); } match req.send().await { ``` ### Technical Analysis Webhook URLs are accepted as arbitrary strings and passed directly to `reqwest::Client::post` without requiring the HTTPS scheme. When a token is configured, it is attached as an `Authorization: Bearer` header. Payment-event JSON is also included in the request body. If an operator supplies an `http://` endpoint, both the Bearer token and financial event metadata can traverse the network without transport encryption. This behavior is related to the declared webhook feature and is not covert exfiltration, but permitting insecure transport is unnecessary for ordinary production operation and violates least-privilege handling of wallet-related information. The event payload may include payment identifiers, hashes, amounts, transaction IDs, channel information, and, for successful outgoing payments, a payment preimage. ### Attack Path 1. An operator configures an `http://` webhook, pot ...[truncated 933 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/main.rs:379
Finding

Wallet Events Are Acknowledged Before Detached Webhook Deliveries Succeed

Content
View full analysis
break, Ok(resp) if resp.status().is_server_error() => { if attempt < max_retries { let delay = 1u64 << attempt; eprintln!("Webhook {url} returned {}, retrying in {delay}s...", resp.status()); tokio::time::sleep(std::time::Duration::from_secs(delay)).await; } else { eprintln!("Webhook {url} returned {} after {max_retries} retries, giving up", resp.status()); } } Ok(resp) => { // 4xx client errors — don't retry eprintln!("Webhook {url} returned {}", resp.status()); break; } Err(e) => { if attempt < max_retries { let delay = 1u64 << attempt; eprintln!("Webhook {url} failed: {e}, retrying in {delay}s..."); tokio::time::sleep(std::time::Duration::from_secs(delay)).await; } else { eprintln!("Webhook {url} failed after {max_retries} retries: {e}"); } } } ...[truncated 2103 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

Chaining Abuse

High
Category
Tool Misuse
Confidence
94% confidence
Finding

Piping network-fetched content directly into a shell removes any opportunity for inspection and makes compromise of the source or delivery path immediately result in code execution. In the context of a wallet skill handling money, compromise of the install path is especially dangerous because it can lead to seed theft, credential theft, or malicious wallet behavior on the host.

Content

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

sh
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install protoc (Ubuntu/Debian — see SKILL.md for other platforms)
sudo apt install -y protobuf-compiler

Chaining Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The | sh construct is a classic command-chaining pattern that turns remote content retrieval directly into code execution. In the context of a wallet tool handling money and secrets, compromise of this step could expose seed material, alter transaction behavior, or implant persistent malware.

Content

Scanner excerpt · SKILL.md (reported line 17)May include surrounding context.

Rust — Install via rustup:

sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

protoc (Protocol Buffers compiler) — Required by the Spark SDK dependency:

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 21)May include surrounding context.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Install protoc (Ubuntu/Debian — see SKILL.md for other platforms)

sudo apt install -y protobuf-compiler

text

```sh

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 · SKILL.md (reported line 24)May include surrounding context.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Install protoc (Ubuntu/Debian — see SKILL.md for other platforms)

sudo apt install -y protobuf-compiler

text

```sh

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 · SKILL.md (reported line 30)May include surrounding context.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Install protoc (Ubuntu/Debian — see SKILL.md for other platforms)

sudo apt install -y protobuf-compiler

text

```sh

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README states that a wallet seed is automatically generated and stored on disk, but does not prominently warn that the seed is the root secret controlling funds and must be backed up and protected. Users may leave the seed unencrypted, include it in backups or shared storage, or fail to back it up at all, leading to theft or irreversible fund loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README encourages sending wallet event data to arbitrary external webhook endpoints but does not clearly warn that those events may contain sensitive financial metadata or that bearer tokens and transport security must be protected. In a wallet-for-agents context, this omission can lead operators to expose payment details, wallet activity, or automation triggers to third-party services without understanding the privacy and security consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation encourages posting wallet event data to arbitrary webhook endpoints and optionally attaching bearer tokens, but it does not prominently warn that payment metadata, identifiers, and operational details are disclosed to third parties. It also states events are marked handled even after repeated delivery failures, which can cause silent event loss and operational integrity issues if a webhook is misconfigured or hostile.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code generates a wallet mnemonic and writes it directly to a predictable file on disk using default filesystem permissions, with only a generic stderr message. A plaintext seed is highly sensitive secret material; if local users, backups, malware, container volume mounts, or misconfigured permissions expose that file, an attacker can take full control of wallet funds.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The send command parses a user-supplied payment target and immediately initiates payment without an interactive confirmation step, preview, or irreversible-action warning. In a wallet CLI, this increases the risk of accidental or socially engineered payments, especially when combined with pasted invoices, BIP21 URIs, or scripts invoking the command non-interactively.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The daemon accepts arbitrary webhook URLs and posts wallet event data to them, including payment identifiers, hashes, txids, channel metadata, and timing information. In a wallet CLI context this can disclose sensitive financial activity to unintended third parties, and the code only logs configured webhooks rather than presenting a clear opt-in warning or restricting destinations.

Content

No source excerpt is available for this finding.

External Script Fetching

Low
Category
Supply Chain
Confidence
89% confidence
Finding

The README instructs users to fetch and immediately execute a remote script with curl piped to sh. If the remote host, connection, or delivered script is compromised, users could execute attacker-controlled code on their machine during installation.

Content

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

sh
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install protoc (Ubuntu/Debian — see SKILL.md for other platforms)
sudo apt install -y protobuf-compiler

External Script Fetching

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The documentation instructs users to fetch and immediately execute a remote script with curl piped into sh. If the remote host, CDN, DNS, TLS trust chain, or the script itself is compromised, arbitrary code executes on the user's machine without review.

Content

Scanner excerpt · SKILL.md (reported line 17)May include surrounding context.

Rust — Install via rustup:

sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

protoc (Protocol Buffers compiler) — Required by the Spark SDK dependency:

Static analysis

No suspicious patterns detected.