Back to skill

Security audit

Smithnode

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real AI blockchain validator, but it needs Review because it can automatically download, replace, and restart its own executable and performs other high-impact network actions with limited user control.

Install only after reviewing the source and running it on an isolated host or container. Avoid public RPC unless protected by firewall/authentication, keep key files chmod 600, prefer environment or secret-manager API keys over command-line arguments, do not provide GitHub credentials unless contributing code, and treat automatic updates as high trust in the SmithNode operator key.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (8)

T03 · Remote Payload Retrieval and Execution

Error
Location
smithnode-core/src/main.rs:1568
Finding

Automatic Remote Binary Replacement and Execution

Content
View full analysis
{ match response.bytes().await { Ok(bytes) => { use sha2::{Sha256, Digest}; let mut hasher = Sha256::new(); hasher.update(&bytes); let computed_checksum = hex::encode(hasher.finalize()); if computed_checksum != checksum { tracing::warn!("⚠️ [{}] Checksum mismatch from {}", source, try_url); continue; } downloaded_bytes = Some(bytes.to_vec()); download_success = true; break; } Err(e) => { tracing::warn!("⚠️ [{}] Failed to read response: {}", source, e); continue; } } } Ok(response) => { tracing::warn!("⚠️ [{}] HTTP {}", source, response.status()); continue; } Err(e) => { tracing::warn!("⚠️ [{}] Download failed: {}", source, e); continue; } } let bytes = downloaded_bytes.unwrap(); match std::env::current_exe() { Ok(current_exe) => { let backup_path = current_exe.with_extension("old"); let new_path = current_exe.with_extension("new"); if let Err(e) = std::fs::write(&new_path, &bytes) { tracing::error!("❌ Failed to write new binary: {}", e); applied_version = Some(upgrade.version.clone()); continue; } #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let _ = std::fs::set_permissions( &new_path, std::fs::Permissions::from_mode(0o755), ); ...[truncated 3120 chars]
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
DEPLOYMENT.md:78
Finding

Remote Installation Scripts Are Piped Directly into a Shell

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
smithnode-core/src/p2p/mod.rs:2169
Finding

Unauthenticated Peer State Can Replace Local Consensus State

Content
View full analysis
(data) { let our_height = self.state.get_height(); if response.height > our_height { let validators: Vec = response.validators.iter() .filter_map(|v| { let pubkey_bytes = hex::decode(&v.public_key).ok()?; if pubkey_bytes.len() != 32 { return None; } let mut pubkey = [0u8; 32]; pubkey.copy_from_slice(&pubkey_bytes); Some(crate::stf::ValidatorInfo { public_key: pubkey, balance: v.balance, validations_count: v.validations_count, reputation_score: v.reputation_score, last_active_timestamp: v.last_active_timestamp, last_validation_height: 0, is_online: true, nonce: v.nonce, }) }) .collect(); let state_root_bytes = hex::decode(&response.state_root).unwrap_or_default(); let mut state_root = [0u8; 32]; if state_root_bytes.len() == 32 { state_root.copy_from_slice(&state_root_bytes); } if self.state.apply_peer_state( response.height, state_root, response.total_supply, validators, ) { tracing::info!("✅ P2P layer applied state sync: now at height {}", response.height); } } } ``` ```rust pub fn apply_peer_state( &self, height: u64, claimed_state_root: [u8; 32], total_supply: u64, validators: Vec, ) -> bool { let mut inne ...[truncated 2601 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
smithnode-core/src/p2p/mod.rs:700
Finding

Unsigned Peer Relay URLs Enable SSRF and Resource Exhaustion

Content
View full analysis
= MAX_PEER_RELAYS { let drain_count = list.len() / 4; list.drain(0..drain_count); } list.push(relay); } } ``` ```rust async fn handle_peer_relay_message(&mut self, data: &[u8]) { match serde_json::from_slice::(data) { Ok(relay) => { tracing::info!( "🌱 Peer {} is relaying v{} for {} at {}", &relay.peer_id[..12.min(relay.peer_id.len())], relay.version, relay.platform, relay.relay_url ); record_peer_relay(relay); } Err(e) => { tracing::debug!("Failed to parse peer relay message: {}", e); } } } ``` ```rust let peer_relays = p2p::get_relay_urls(&upgrade.version, &download_key); let mut try_urls: Vec = peer_relays; try_urls.push(url.clone()); for (i, try_url) in try_urls.iter().enumerate() { let source = if i < try_urls.len() - 1 { "P2P relay" } else { "HTTP" }; match reqwest::get(try_url).await { Ok(response) if response.status().is_success() => { match response.bytes().await ...[truncated 2727 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
smithnode-core/src/main.rs:281
Finding

Private Keys Are Created Without Enforced Restrictive Permissions

Content
View full analysis
= serde_json::from_str(&key_data)?; ed25519_dalek::SigningKey::from_bytes(&key_bytes.try_into().unwrap_or([0u8; 32])) } else { let mut rng = rand::rngs::OsRng; let key = ed25519_dalek::SigningKey::generate(&mut rng); let key_bytes = key.to_bytes().to_vec(); std::fs::write(&node_keypair_path, serde_json::to_string(&key_bytes)?)?; key }; ``` ```rust let keypair = serde_json::json!({ "private_key": hex::encode(signing_key.to_bytes()), "public_key": hex::encode(verifying_key.to_bytes()), }); if let Some(path) = output { std::fs::write(&path, serde_json::to_string_pretty(&keypair)?)?; tracing::info!("Keypair written to {:?}", path); } else { println!("{}", serde_json::to_string_pretty(&keypair)?); } ``` ### Technical Analysis Private key material is written using `std::fs::write`, which does not explicitly create the file with mode `0600`. The resulting permissions depend on the process umask. On a permissively configured system, group members or other local users may be able to read the file. Permissions are not established atomically, and the output path is not protected with create-new or no-follow semantics. The validator key generator also prints the complete private key to standard output when no output path is supplied, increasing the risk of capture by terminal logs or automation. ### Attack Path 1. An operator runs key generation under a permissive umask or writes into an unsafe directory. 2. The key file is created with permissions that allow another local account ...[truncated 497 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
smithnode-core/src/main.rs:986
Finding

Autonomous Governance Voting Fails Open and Processes Proposal-Controlled Text

Content
View full analysis
format!("Current reward: {} SMITH → Proposed: {} SMITH", current_params.reward_per_proof, new_value), stf::ProposalType::ChangeCommitteeSize { new_value } => format!("Current committee size: {} → Proposed: {}", current_params.committee_size, new_value), stf::ProposalType::ChangeMinStake { new_value } => format!("Current min stake: {} SMITH → Proposed: {} SMITH", current_params.min_validator_stake, new_value), stf::ProposalType::ChangeSlashPenalty { new_value } => format!("Current slash penalty: {}% → Proposed: {}%", current_params.slash_percentage, new_value), stf::ProposalType::ChangeAIRateLimit { new_value } => format!("Current AI rate limit: {}s → Proposed: {}s", current_params.ai_rate_limit_secs, new_value), stf::ProposalType::ChangeMaxValidators { new_value } => format!("Current max validators: {} → Proposed: {}", current_params.max_validators, new_value), stf::ProposalType::Emergency { action } => format!("Emergency action: {}", action), }; let prompt = format!( "SmithNode governance vote. {current_value_info}\n\ Network: {total_supply} SMITH supply, {annual_inflation_pct}% inflation, {total_validator_count} validators, {stake_ratio}% staked.\n\ Should this change be approved? Reply YES or NO then explain why in 1-2 sentences.", current_value_info = current_value_info, total_supply = total_supply, annual_inflation_pct = annual_inflation_pct, total_validator_count = total_validator_count, stake_ratio = stake_ratio, ); let (vote_decision, reason) = match ai_for_gov.solve_puzzle(&prompt).await { Ok(answer) ...[truncated 2008 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
VALIDATOR_GUIDE.md:153
Finding

Cloud AI API Keys Are Passed Through Process Arguments

Content
View full analysis
{ let key = ai_api_key.as_deref() .expect("--ai-api-key required for Anthropic"); let mut config = ai::AIConfig::anthropic(key); if let Some(ref model) = ai_model { config.model = model.clone(); } config } ``` ```rust let args: Vec = std::env::args().collect(); #[cfg(unix)] { use std::os::unix::process::CommandExt; let err = std::process::Command::new(¤t_exe) .args(&args[1..]) .exec(); tracing::error!("❌ Failed to re-exec: {}", err); let _ = std::fs::rename(&backup_path, ¤t_exe); } ``` ### Technical Analysis The documented and implemented interface accepts provider API credentials as command-line arguments. Process arguments may be visible through operating-system process inspection, service-manager metadata, diagnostic collection, shell history, audit logs, and monitoring tools. The self-update process reconstructs and reuses the complete original argument list, preserving the credential-bearing argument across automatic re-execution. Although `skill.md` recommends environment variables in some examples, the primary validator CLI shown in the guides encourages direct argument use. ### Attack Path 1. An operator starts the validator with `--ai-api-key `. 2. The full command is retained in shell history or ...[truncated 466 chars]
Remediation
View remediation

T06 · System Persistence

Error
Location
VALIDATOR_GUIDE.md:382
Finding

Root-Assisted Persistent System Service Installation

Content
View full analysis
/dev/null <
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (105)

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
100% confidence
Finding

The code explicitly self-modifies by replacing its own executable with downloaded content and then executing it. Any weakness in upgrade announcement trust, key management, relay/source integrity, or local filesystem protections turns this into a direct path to persistent arbitrary code execution on validator hosts.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · AI_CONTRIBUTOR_GUIDE.md (reported line 193)May include surrounding context.

text

3. Add test
4. Update SKILL.md docs

### Fixing a Bug

Chaining Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

The '| sh' pattern is a high-risk command chaining construct because it immediately executes untrusted remote content in the shell. In deployment documentation, this can lead users to run attacker-controlled code if the remote endpoint, DNS, TLS trust chain, or distribution channel is compromised.

Content

Scanner excerpt · DEPLOYMENT.md (reported line 81)May include surrounding context.

md
# Option A (Manual - Recommended): Download from https://www.rust-lang.org/tools/install
# Option B (Script):
# ⚠️ WARNING: This runs a third-party script. Review at https://sh.rustup.rs first.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# 2. Clone and build

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description broadly matches the core theme: this is indeed a P2P blockchain node for AI agents with validator logic, P2P networking, RPC, and AI integrations including Ollama and cloud providers. However, the supplied code chunk contains materially significant capabilities not reflected in the description or permissions: it can announce software upgrades, poll an RPC endpoint for upgrades, download binaries from peers or HTTP sources, verify checksums, replace its own executable on disk, and restart itself. Those are powerful operational capabilities beyond simply being a blockchain for AI agents, and they involve filesystem modification and remote code/update retrieval. Because these undeclared behaviors are substantial and security-relevant, the description does not accurately represent the full behavior of the code.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
99% confidence
Finding

Piping a remotely fetched script directly into sh executes third-party code without pinning, signature verification, or a mandatory review step. Although the guide includes a warning, this pattern remains dangerous because compromise of the source, CDN, DNS, or TLS trust chain can lead to immediate code execution on the operator's machine.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 131)May include surrounding context.

bash
# ⚠️ WARNING: This runs a third-party script on your machine.
# Review the script first: https://ollama.ai/install.sh
curl -fsSL https://ollama.ai/install.sh | sh

Then pull a model and run:

Chaining Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

curl ... | sh chains remote content retrieval directly into shell execution, removing the operator's chance to inspect what will run. In a validator setup guide, this is especially risky because users are likely to run it on always-on hosts that may hold keys or trusted infrastructure access.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 131)May include surrounding context.

bash
# ⚠️ WARNING: This runs a third-party script on your machine.
# Review the script first: https://ollama.ai/install.sh
curl -fsSL https://ollama.ai/install.sh | sh

Then pull a model and run:

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 211)May include surrounding context.

bash
# Your local node
curl -s -X POST http://127.0.0.1:26658 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"smithnode_status","params":[],"id":1}' | python3 -m json.tool

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 216)May include surrounding context.

-d '{"jsonrpc":"2.0","method":"smithnode_status","params":[],"id":1}' | python3 -m json.tool

Network sequencer

curl -s -X POST https://smithnode-rpc.fly.dev
-H "Content-Type: application/json"
-d '{"jsonrpc":"2.0","method":"smithnode_status","params":[],"id":1}' | python3 -m json.tool

text

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 225)May include surrounding context.

bash
# Replace YOUR_PUBLIC_KEY with your key from my-keypair.json
curl -s -X POST https://smithnode-rpc.fly.dev \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"smithnode_getValidator","params":["YOUR_PUBLIC_KEY"],"id":1}' | python3 -m json.tool

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 233)May include surrounding context.

View All Validators

bash
curl -s -X POST https://smithnode-rpc.fly.dev \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"smithnode_getValidators","params":[],"id":1}' | python3 -m json.tool

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 255)May include surrounding context.

View Current Parameters

bash
curl -s -X POST https://smithnode-rpc.fly.dev \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"smithnode_getNetworkParams","params":[],"id":1}' | python3 -m json.tool

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · VALIDATOR_GUIDE.md (reported line 353)May include surrounding context.

To check for updates manually:

bash
curl -s -X POST https://smithnode-rpc.fly.dev \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"smithnode_checkUpdate","params":[],"id":1}' | python3 -m json.tool

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · skill.md (reported line 97)May include surrounding context.

md
| `cargo` (Rust 1.70+) | Compile the validator binary |
| `curl` | Download dependencies, health checks |

> **⚠️ Remote Install Scripts:** Some guides show `curl | sh` commands for installing Rust/Ollama. These run third-party code. Prefer manual installs from official release pages when possible.

### Runtime Permissions

Self-Modification

High
Category
Rogue Agent
Confidence
90% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · skill.md (reported line 425)May include surrounding context.

md
- No private key exfiltration
- No unexpected outbound traffic
- No filesystem abuse
- No self-modifying behavior

---

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Validator mode includes an autonomous update path that downloads a new binary, writes it to disk, swaps the current executable, and re-execs the process. Even though signatures/checksums are partially checked upstream, this is still a powerful remote code execution mechanism embedded in a blockchain node and materially expands the trust boundary beyond the stated runtime consensus role.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The validator automatically performs upgrade download, install, and restart without an explicit user confirmation step. In a decentralized P2P context, this creates a dangerous silent-update channel where operators may unknowingly run new code, magnifying the impact of compromised signing keys, bad releases, or logic flaws in the update pipeline.

Content

No source excerpt is available for this finding.

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · smithnode-core/src/stf/state.rs (reported line 1871)May include surrounding context.

rust
// Reset state.json to empty genesis (overwrite, not delete - safer for sandboxed envs)
        if let Err(e) = self.storage.reset_state_file() {
            tracing::warn!("⚠️ Failed to reset state file during chain reset: {}", e);
        }
        
        // Truncate WAL

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · smithnode-core/src/stf/state.rs (reported line 1846)May include surrounding context.

rust
self.data_dir.join("state.json")
    }

    /// Reset state file to fresh genesis (safer than delete))
    pub fn reset_state_file(&self) -> anyhow::Result<()> {
        let path = self.state_path();
        // Write an empty genesis state instead of deleting (safer for sandboxed environments)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · smithnode-core/src/stf/state.rs (reported line 1869)May include surrounding context.

rust
self.data_dir.join("state.json")
    }

    /// Reset state file to fresh genesis (safer than delete))
    pub fn reset_state_file(&self) -> anyhow::Result<()> {
        let path = self.state_path();
        // Write an empty genesis state instead of deleting (safer for sandboxed environments)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · smithnode-core/src/storage/mod.rs (reported line 118)May include surrounding context.

rust
self.data_dir.join("state.json")
    }

    /// Reset state file to fresh genesis (safer than delete))
    pub fn reset_state_file(&self) -> anyhow::Result<()> {
        let path = self.state_path();
        // Write an empty genesis state instead of deleting (safer for sandboxed environments)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · smithnode-core/src/storage/mod.rs (reported line 125)May include surrounding context.

rust
self.data_dir.join("state.json")
    }

    /// Reset state file to fresh genesis (safer than delete))
    pub fn reset_state_file(&self) -> anyhow::Result<()> {
        let path = self.state_path();
        // Write an empty genesis state instead of deleting (safer for sandboxed environments)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · AI_CONTRIBUTOR_GUIDE.md (reported line 19)May include surrounding context.

md
- Only provide tokens with **minimum required scope** (`public_repo` for public repos)
- Prefer human-mediated GitHub operations when possible
- Never store tokens in world-readable locations or commit them
- Revoke tokens after completing contribution work

**If you only want to run a validator, STOP HERE and see [VALIDATOR_GUIDE.md](VALIDATOR_GUIDE.md).**

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · DEPLOYMENT.md (reported line 52)May include surrounding context.

VITE_WS_URL=wss://your-public-node.com:26658

text

### Option C: GitHub Auto-Deploy

1. Push to GitHub
2. Go to [vercel.com](https://vercel.com)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The guide instructs operators to bind RPC and P2P services to 0.0.0.0 and open firewall ports, which makes the node reachable from the public internet. While this is sometimes required for a public blockchain node, the documentation does not clearly describe authentication, rate-limiting, network ACLs, or the attack surface of exposing RPC, so users may unintentionally deploy an insecure public endpoint.

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

--p2p-bind 0.0.0.0:26656

4. Open firewall ports

sudo ufw allow 26658 # RPC sudo ufw allow 26656 # P2P

text

Static analysis

No suspicious patterns detected.