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<![CDATA[ ## Vulnerability Details **File Location**: `smithnode-core/src/main.rs:1568-1822` **Vulnerability Type**: Unattended remote software download, executable replacement, and process re-execution **Risk Level**: Critical ### Vulnerable Code ```rust match reqwest::get(try_url).await { Ok(response) if response.status().is_success() => { 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
<![CDATA[ ## Remediation Suggestions - Remove automatic executable replacement and re-execution from the validator. - Require an explicit administrator action before installing every release. - Use reproducible builds and publish verifiable source-to-binary attestations. - Require threshold signatures from multiple independently controlled release keys. - Pin allowed release origins and require HTTPS without unsafe redirects. - Stage updates in an isolated directory and verify signatures using an offline release root. - Run update installation through a separate, narrowly privileged updater that cannot read validator keys. - Provide a configuration option that disables remote updates by default. - Add release-key rotation and revocation procedures. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
DEPLOYMENT.md:78
Finding
Remote Installation Scripts Are Piped Directly into a Shell<![CDATA[ ## Vulnerability Details **File Location**: `DEPLOYMENT.md:78-81`; `VALIDATOR_GUIDE.md:124-131` **Vulnerability Type**: Execution of mutable third-party installation scripts **Risk Level**: High ### Vulnerable Code ```bash # Option A (Manual - Recommended): Download from https://www.rust-lang.org/tools/install # ⚠️ 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 ``` ```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 ``` ### Technical Analysis Both commands stream mutable remote content directly into a command interpreter. There is no pinned version, digest, detached signature, or opportunity to verify that the bytes executed are the bytes previously reviewed. TLS protects the connection but does not make the remote content immutable. A compromised hosting account, origin server, DNS/TLS trust chain, or upstream distribution mechanism can change the effective payload after the Skill has been audited. The accompanying warnings and manual alternatives are beneficial, but they do not eliminate the unsafe executable instructions. ### Attack Path 1. An attacker compromises one of the installer origins or its delivery chain. 2. The remote installer is modified to include attacker-controlled shell commands. 3. An operator follows the documented command. 4. `curl` streams the modified content directly into `sh`. 5. The payload executes with the privileges of the invoking user, potentially including elevated privileges requested by the installer. ### Impact Assessment The payload can execute arbitrary shell commands, modify user files, install software, access credentials, establish persistence, or invoke privilege-elevation mechanisms. The exact scope depends on the invoking account and actions performed by the remote script. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove all `curl | sh` installation examples. - Download a versioned release artifact to disk as a separate step. - Verify a pinned SHA-256 digest and a detached signature from a documented release key. - Inspect the downloaded script or package before execution. - Prefer operating-system package managers or signed, versioned release packages. - Pin exact dependency and installer versions rather than mutable latest URLs. - Document cleanup and verification commands. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
smithnode-core/src/p2p/mod.rs:2169
Finding
Unauthenticated Peer State Can Replace Local Consensus State<![CDATA[ ## Vulnerability Details **File Location**: `smithnode-core/src/p2p/mod.rs:2169-2284`; `smithnode-core/src/stf/state.rs:336-413` **Vulnerability Type**: Missing authentication and cryptographic verification on state synchronization **Risk Level**: High ### Vulnerable Code ```rust if let Ok(response) = serde_json::from_slice::<StateResponseMessage>(data) { let our_height = self.state.get_height(); if response.height > our_height { let validators: Vec<crate::stf::ValidatorInfo> = 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<ValidatorInfo>, ) -> bool { let mut inne ...[truncated 2601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Sign state responses and verify the signer against an authenticated validator identity. - Bind the response identity to the libp2p transport peer rather than trusting a serialized `responder_peer_id`. - Accept only responses corresponding to an outstanding request. - Require a finalized checkpoint, quorum certificate, or equivalent consensus proof. - Recompute the complete state commitment from canonical serialized snapshot data. - Validate validator uniqueness, supply invariants, nonces, and all consensus-critical fields. - Compare responses from multiple independent peers before applying a checkpoint. - Add recovery logic for invalid high-height snapshots and tests for forged state responses. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
smithnode-core/src/p2p/mod.rs:700
Finding
Unsigned Peer Relay URLs Enable SSRF and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `smithnode-core/src/p2p/mod.rs:700-751,2379-2392`; `smithnode-core/src/main.rs:1663-1724` **Vulnerability Type**: Unvalidated peer-controlled URL retrieval and unbounded response buffering **Risk Level**: High ### Vulnerable Code ```rust #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PeerRelayAnnouncement { pub version: String, pub platform: String, pub relay_url: String, pub checksum: String, pub peer_id: String, pub timestamp: u64, } pub fn record_peer_relay(relay: PeerRelayAnnouncement) { let relays = get_peer_relays(); let mut list = relays.write_or_recover(); if !list.iter().any(|r| r.peer_id == relay.peer_id && r.version == relay.version && r.platform == relay.platform) { if list.len() >= 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::<PeerRelayAnnouncement>(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<String> = 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
<![CDATA[ ## Remediation Suggestions - Cryptographically sign relay announcements and bind the signer to the authenticated transport peer. - Derive reachable relay addresses from authenticated peer connection data rather than arbitrary serialized URLs. - Permit only an explicitly defined HTTPS or authenticated P2P relay protocol. - Reject loopback, private, link-local, multicast, and cloud metadata destinations after DNS resolution. - Revalidate every redirect target or disable redirects entirely. - Enforce strict connection, read, and total-request timeouts. - Stream downloads while enforcing a small maximum size. - Verify the expected operator-signed checksum during streaming. - Validate relay timestamps and rate-limit announcements per authenticated peer. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
smithnode-core/src/main.rs:281
Finding
Private Keys Are Created Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `smithnode-core/src/main.rs:281-290,580-598` **Vulnerability Type**: Insecure creation of plaintext private-key files **Risk Level**: Medium ### Vulnerable Code ```rust let node_keypair_path = data_dir.join("node_key.json"); let node_signing_key = if std::path::Path::new(&node_keypair_path).exists() { let key_data = std::fs::read_to_string(&node_keypair_path)?; let key_bytes: Vec<u8> = 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
<![CDATA[ ## Remediation Suggestions - On Unix, create key files atomically with mode `0600` using `OpenOptionsExt::mode`. - Use create-new semantics to avoid overwriting existing files. - Reject symbolic links and unsafe parent directories. - Verify permissions when loading an existing private-key file and fail if they are too broad. - Avoid printing private keys to standard output by default. - Use an encrypted keystore or operating-system secret store where practical. - Document secure backup procedures without recommending plaintext copies. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
smithnode-core/src/main.rs:986
Finding
Autonomous Governance Voting Fails Open and Processes Proposal-Controlled Text<![CDATA[ ## Vulnerability Details **File Location**: `smithnode-core/src/main.rs:986-1144` **Vulnerability Type**: Fail-open authorization decision and AI prompt injection exposure **Risk Level**: High ### Vulnerable Code ```rust let current_value_info = match &proposal.proposal_type { stf::ProposalType::ChangeReward { new_value } => 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
<![CDATA[ ## Remediation Suggestions - Abstain or fail closed on every AI provider error, timeout, or malformed answer. - Accept only an exact, schema-validated `YES` or `NO` decision. - Treat all proposal text as untrusted data and clearly delimit or encode it. - Do not allow free-form emergency actions to control model instructions. - Apply deterministic local policy limits before asking an AI model. - Require explicit operator confirmation for emergency and high-impact votes. - Record the complete decision input and validated output for auditability without recording secrets. - Add tests covering refusals, ambiguous responses, injection attempts, timeouts, and provider errors. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
VALIDATOR_GUIDE.md:153
Finding
Cloud AI API Keys Are Passed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `VALIDATOR_GUIDE.md:153-175,363-375`; `smithnode-core/src/main.rs:891-921,1814-1821` **Vulnerability Type**: Sensitive credentials exposed through command-line arguments **Risk Level**: Medium ### Vulnerable Code ```bash ./smithnode validator ... \ --ai-provider openai \ --ai-api-key sk-your-key \ --ai-model gpt-4-turbo-preview ./smithnode validator ... \ --ai-provider anthropic \ --ai-api-key sk-ant-your-key \ --ai-model claude-3-sonnet-20240229 ./smithnode validator ... \ --ai-provider groq \ --ai-api-key gsk_your-key \ --ai-model llama-3.1-70b-versatile ``` ```rust "anthropic" => { 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<String> = std::env::args().collect(); #[cfg(unix)] { use std::os::unix::process::CommandExt; let err = std::process::Command::new(&current_exe) .args(&args[1..]) .exec(); tracing::error!("❌ Failed to re-exec: {}", err); let _ = std::fs::rename(&backup_path, &current_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 <secret>`. 2. The full command is retained in shell history or ...[truncated 466 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Deprecate and remove secret-bearing command-line options. - Load provider credentials from protected files, standard input, an OS credential store, or provider-specific environment variables. - Prefer file descriptor or secret-manager integration for long-running services. - Ensure diagnostics and logs redact secrets. - Warn users if a credential is supplied through argv during a transition period. - Update every guide and service example to use the secure credential mechanism. ]]>

T06 · System Persistence

Error
Location
VALIDATOR_GUIDE.md:382
Finding
Root-Assisted Persistent System Service Installation<![CDATA[ ## Vulnerability Details **File Location**: `VALIDATOR_GUIDE.md:382-407` **Vulnerability Type**: Cross-session service registration with automatic restart **Risk Level**: High ### Vulnerable Code ```bash sudo tee /etc/systemd/system/smithnode.service > /dev/null <<EOF [Unit] Description=SmithNode P2P Validator After=network-online.target Wants=network-online.target [Service] Type=exec User=$USER WorkingDirectory=$HOME ExecStart=$HOME/smithnode validator \ --keypair $HOME/.smithnode/keypair.json \ --peer /ip4/168.220.90.95/tcp/26656/p2p/12D3KooWLC8dxuQAi7czdCALNqjoF3QkDsL7wALxJGzQA5TEnsrQ \ --sequencer-rpc https://smithnode-rpc.fly.dev \ --rpc-bind 127.0.0.1:26658 Restart=always RestartSec=5 LimitNOFILE=65536 Environment=RUST_LOG=info [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now smithnode sudo journalctl -u smithnode -f ``` ### Technical Analysis The guide directs users to use `sudo` to write a system-level unit and enable it at boot. The service then automatically restarts the validator after failures. Long-running service operation is relevant to validator availability, but system-wide registration exceeds the least privilege necessary for ordinary validator execution and conflicts with the Skill documentation stating that validator operation does not require root or sudo access. The persistence mechanism compounds the automatic update vulnerability: a malicious or compromised replacement executable continues to run after process failures and system reboots. ### Attack Path 1. An operator follows the systemd deployment instructions. 2. Root privileges are used to install and enable the service. 3. The validator starts automatically at boot and restarts after termination. 4. A compromised signed update replaces the validator executable. 5. The service repeatedly launches the replacement executable across failures and reboots. ### Impact Assessment The service establishes durable ...[truncated 258 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Clearly label service installation as optional production deployment rather than normal Skill operation. - Prefer a rootless systemd user service with `systemctl --user`. - Provide explicit disable, uninstall, and cleanup instructions. - Harden the service with `NoNewPrivileges`, `ProtectSystem`, `ProtectHome`, `PrivateTmp`, restricted address families, and narrowly scoped writable paths. - Store keys outside the executable directory with restrictive permissions. - Avoid `Restart=always` after integrity or update verification failures. - Disable automatic executable updates for persistent deployments or isolate updates in a separately privileged component. ]]>
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
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.

Self-Modification

High
Category
Rogue Agent
Content
```

3. Add test
4. Update SKILL.md docs

### Fixing a Bug
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.

Chaining Abuse

High
Category
Tool Misuse
Content
# 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
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.

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.

External Script Fetching

High
Category
Supply Chain
Content
```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:**
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.

Chaining Abuse

High
Category
Tool Misuse
Content
```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:**
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.

External Script Fetching

High
Category
Supply Chain
Content
```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
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
-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
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
```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
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
### 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
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
### 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
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
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
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
| `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
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Self-Modification

High
Category
Rogue Agent
Content
- No private key exfiltration
- No unexpected outbound traffic
- No filesystem abuse
- No self-modifying behavior

---
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.

Description-Behavior Mismatch

High
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.

Missing User Warnings

High
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.

Memory Manipulation

High
Category
Memory Poisoning
Content
// 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
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Memory Manipulation

High
Category
Memory Poisoning
Content
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)
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Memory Manipulation

High
Category
Memory Poisoning
Content
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)
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Memory Manipulation

High
Category
Memory Poisoning
Content
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)
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Memory Manipulation

High
Category
Memory Poisoning
Content
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)
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
- 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).**
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.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# VITE_WS_URL=wss://your-public-node.com:26658
```

### Option C: GitHub Auto-Deploy

1. Push to GitHub
2. Go to [vercel.com](https://vercel.com)
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.

Missing User Warnings

Medium
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
--p2p-bind 0.0.0.0:26656

# 4. Open firewall ports
sudo ufw allow 26658  # RPC
sudo ufw allow 26656  # P2P
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.