Back to skill

Security audit

Solidity Guardian

Security checks for vulnerabilities and agentic risk

Overview

This smart-contract scanner is purpose-aligned, but it needs review because its Slither wrapper can run unsafe shell commands from a crafted path and can install unpinned tools.

Review before installing. Use it only on trusted local paths, avoid passing untrusted or generated path strings to slither-integration.js, and prefer preinstalling a pinned Slither version in an isolated environment instead of using --install-slither. Do not run it as root or in a CI job with broad secrets until the shell command construction is fixed.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
slither-integration.js:73
Finding

Shell Command Injection Through the Project Path

Content
View full analysis

Vulnerability Details

File Location: slither-integration.js:73-79
Vulnerability Type: OS command injection
Risk Level: High

javascript
// Run Slither with JSON output
const cmd = `slither ${projectPath} --json ${outputFile} 2>/dev/null`;
execSync(cmd, { 
  stdio: 'pipe',
  timeout: 300000, // 5 minute timeout
  cwd: projectPath.includes('/') ? path.dirname(projectPath) : process.cwd()
});

Technical Analysis

projectPath originates from the first command-line argument and is interpolated directly into a command string passed to execSync. When Node.js receives a string in this form, it executes the command through a system shell.

No quoting, escaping, allowlist validation, or shell-metacharacter rejection is applied. An attacker who can control the project path can therefore inject command separators, substitutions, redirections, or other shell syntax. The exception handler does not prevent exploitation because the injected command runs before control returns to JavaScript.

Attack Path

  1. The attacker gains control over the target path passed to the integration, such as through an automated audit service, CI job parameter, or wrapper application.
  2. The attacker supplies a shell payload as the path:
    bash
    node slither-integration.js '.; touch PWNED; #' --slither-only
    
  3. The application constructs a command equivalent to:
    bash
    slither .; touch PWNED; # --json /tmp/slither-....json 2>/dev/null
    
  4. The shell executes touch PWNED independently of Slither.
  5. The attacker can replace that proof-of-concept command with any command available to the process account.

Using --slither-only avoids the earlier fs.statSync(projectPath) call and sends the malicious value directly to runSlither.

Impact Assessment

Successful exploitation provides arbitrary command execution with the operating-system privileges of the Node.js process. An ...[truncated 431 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not construct a shell command from user-controlled input.
  • Replace execSync with spawnSync or execFileSync and pass arguments as an array:
    javascript
    const { spawnSync } = require('child_process');
    
    const result = spawnSync(
      'slither',
      [resolvedProjectPath, '--json', outputFile],
      {
        stdio: 'pipe',
        timeout: 300000,
        cwd: fs.statSync(resolvedProjectPath).isDirectory()
          ? resolvedProjectPath
          : path.dirname(resolvedProjectPath),
        shell: false
      }
    );
    
  • Canonicalize the target with fs.realpathSync and confirm it exists before execution.
  • If the application restricts audits to a workspace, verify that the canonical path remains inside that workspace.
  • Reject unexpected option-like paths or terminate utility options with -- if Slither supports it.
  • Run analysis under a dedicated, unprivileged account with restricted filesystem and network access.
  • Add regression tests using paths containing spaces and shell characters such as ;, $(), backticks, pipes, and redirections.

T08 · Insecure Dependencies

Warning
Location
slither-integration.js:20
Finding

Unpinned Third-Party Package Installation at Runtime

Content
View full analysis

Vulnerability Details

File Location: slither-integration.js:20-42
Vulnerability Type: Unsafe runtime dependency installation
Risk Level: Medium

javascript
// Install Slither
async function installSlither() {
  console.log('Installing Slither...');
  
  // Try different installation methods
  const methods = [
    'pipx install slither-analyzer',
    'pip3 install slither-analyzer',
    'python3 -m pip install slither-analyzer'
  ];
  
  for (const method of methods) {
    try {
      execSync(method, { stdio: 'inherit' });
      console.log('✅ Slither installed successfully');
      return true;
    } catch {
      continue;
    }
  }
  
  console.log('⚠️  Could not install Slither. Install manually:');
  console.log('   pip3 install slither-analyzer');
  console.log('   or: pipx install slither-analyzer');
  return false;
}

Technical Analysis

When --install-slither is enabled, the Skill installs slither-analyzer without a pinned version or verified hashes. The installed code and its transitive dependency set can therefore change between executions even when the Skill itself has not changed.

Python package installation executes package-controlled build and installation logic. Consequently, compromise of the package source, a dependency, or a future release can result in unreviewed code executing in the audit environment. The pip3 and python3 -m pip fallbacks may also modify the active Python environment rather than a dedicated isolated environment.

Attack Path

  1. Slither is not present on the host.
  2. A user or automated system invokes the integration with --install-slither.
  3. installSlither requests the latest available slither-analyzer release and unresolved transitive dependencies.
  4. The package manager downloads and executes package installation logic from the configured Python package source.
  5. If an upstream package, depend ...[truncated 796 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove automatic package installation from the analysis path where possible.
  • Provision Slither as a reviewed build-time dependency or trusted container image.
  • Pin an audited exact version, including all transitive dependencies.
  • Require package hashes through a locked requirements file, for example with pip --require-hashes.
  • Install dependencies into a dedicated virtual environment rather than the active or system Python environment.
  • Use an explicitly configured trusted package index and secure transport.
  • Record the installed Slither version and dependency lockfile in generated reports for reproducibility.
  • Run package installation and analysis as a non-root user in a sandbox with limited network, filesystem, and credential access.
  • Fail closed if the approved version is unavailable instead of falling back to an unpinned installation.

T09 · Insecure Skill Coding Practices

Warning
Location
slither-integration.js:69
Finding

Predictable Slither Output File in a Shared Temporary Directory

Content
View full analysis

Vulnerability Details

File Location: slither-integration.js:69-90
Vulnerability Type: Insecure temporary-file handling
Risk Level: Medium

javascript
const outputFile = path.join('/tmp', `slither-${Date.now()}.json`);

try {
  // Run Slither with JSON output
  const cmd = `slither ${projectPath} --json ${outputFile} 2>/dev/null`;
  execSync(cmd, { 
    stdio: 'pipe',
    timeout: 300000, // 5 minute timeout
    cwd: projectPath.includes('/') ? path.dirname(projectPath) : process.cwd()
  });
} catch (e) {
  // Slither exits with non-zero on findings, but still writes JSON
}

if (!fs.existsSync(outputFile)) {
  console.log('Slither did not produce output. Check if project compiles.');
  return null;
}

try {
  const results = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
  fs.unlinkSync(outputFile); // Clean up
  return results;

Technical Analysis

The Slither output filename is derived only from the current timestamp and placed directly in the globally shared /tmp directory. The code does not create a private temporary directory, atomically reserve the filename, verify ownership, reject symbolic links, or open the file with exclusive and no-follow protections.

A local attacker able to observe or predict the filename can attempt to pre-create it, replace it, or use a symbolic link. This creates a time-of-check/time-of-use exposure between Slither writing the file, existsSync, and readFileSync.

At minimum, another local process may be able to substitute crafted JSON and compromise report integrity. Depending on how the installed Slither version opens its JSON destination and the permissions of the process, a pre-positioned symbolic link may also redirect its write operation to another file.

Cleanup is only performed after successful JSON parsing. Invalid output or parsing failures leave the temporary artifact behind.

Attack Path

  1. The attacker has l ...[truncated 1371 chars]
Remediation
View remediation

Remediation Suggestions

  • Create a private temporary directory using fs.mkdtempSync:
    javascript
    const os = require('os');
    
    const tempDir = fs.mkdtempSync(
      path.join(os.tmpdir(), 'solidity-guardian-')
    );
    const outputFile = path.join(tempDir, 'slither.json');
    
  • Ensure the directory is accessible only to the current user, using mode 0700 where necessary.
  • Pass the temporary path to Slither through an argument array rather than a shell command.
  • Verify that the result is a regular file located inside the private directory before reading it.
  • Where direct file creation is possible, use exclusive creation and no-follow protections.
  • Place all cleanup in a finally block and recursively remove the private temporary directory:
    javascript
    try {
      // Run Slither and parse the result.
    } finally {
      fs.rmSync(tempDir, { recursive: true, force: true });
    }
    
  • Avoid predictable names in shared directories and do not rely on Date.now() as a uniqueness or security mechanism.
  • Isolate audit jobs from untrusted local users when running on CI infrastructure.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill can automatically install Slither by invoking pipx/pip3/python3 pip on the host, which expands its capability from analysis into host modification and software provisioning. Even if intended as convenience, package installation executes external code and changes the environment, creating supply-chain and integrity risks that are not necessary for a read-only audit workflow.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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 · analyzer.js (reported line 90)May include surrounding context.

js
// Check if it's likely an ERC20 call
      return /\w+\.transfer\s*\(/.test(line) && !/msg\.sender\.transfer|payable\(/.test(line);
    },
    description: 'ERC20 transfer without checking return value. Some tokens return false instead of reverting.',
    suggestion: 'Use SafeERC20.safeTransfer() from OpenZeppelin.',
    references: ['https://swcregistry.io/docs/SWC-104']
  },

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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 · analyzer.js (reported line 308)May include surrounding context.

js
// Check if it's likely an ERC20 call
      return /\w+\.transfer\s*\(/.test(line) && !/msg\.sender\.transfer|payable\(/.test(line);
    },
    description: 'ERC20 transfer without checking return value. Some tokens return false instead of reverting.',
    suggestion: 'Use SafeERC20.safeTransfer() from OpenZeppelin.',
    references: ['https://swcregistry.io/docs/SWC-104']
  },

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script executes external commands on the host (slither --version, installation commands, and the Slither scan itself), which gives the skill code-execution capability beyond pure parsing/report generation. In a security-analysis skill this may be partly expected, but it still increases attack surface because untrusted project paths and tool execution can trigger unintended host-side effects via the external toolchain.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Auto-installing packages without an explicit confirmation prompt means the skill can modify the host environment and fetch/execute third-party code as a side effect of analysis. This is dangerous because users may expect a scan-only operation, while package installation introduces both surprise state changes and supply-chain risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly advertises auto-installing Slither if missing, but does not warn users that running the command may modify the host system by installing packages and dependencies. In a security-analysis skill, hidden environment modification is especially risky because users may trust the tool and execute commands in sensitive CI or developer environments, increasing supply-chain and unintended-change exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code recursively traverses the provided directory and reads every .sol file it finds via analyzeDirectory() and analyzeFile(), which can process large amounts of project source content. Although this behavior is central to the analyzer's purpose, there is no explicit user disclosure in the CLI output or surrounding comments that the supplied path will be recursively scanned and file contents read.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The file is named and invoked as the main executable in this module, but the usage string tells users to run node analyze.js, while the actual file under review is analyzer.js. This is an active documentation-to-code mismatch because the inline CLI help points to a different entrypoint than the code being executed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

Writing directly to a user-specified output path without overwrite protection can clobber existing local files. The impact is limited because the destination is user-provided, but accidental data loss or unintended file modification is still possible.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
slither-integration.js:14