Back to skill

Security audit

Csharp Developer

Security checks for vulnerabilities and agentic risk

Overview

This C# development skill mostly matches its stated purpose, but its project creation command can turn user-controlled options into local shell execution.

Review this before installing. It is not evidence of malicious intent, but only use the project-creation feature with trusted arguments and avoid passing untrusted .NET version or output directory values until the command is changed to safe argument-based execution and inputs are validated.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:88
Finding

OS Command Injection Through Untrusted Project Creation Options

Content
View full analysis

Vulnerability Details

File Location: index.js, lines 88–111
Vulnerability Type: OS command injection through shell command construction
Risk Level: High

Vulnerable Code

javascript
async function createProject(projectType, dotnetVersion, outputDir) {
  const templateMap = {
    'wpf': 'wpf',
    'console': 'console',
    'webapi': 'webapi',
    'classlib': 'classlib',
    'worker': 'worker',
  };

  const template = templateMap[projectType] || 'console';
  const targetDir = outputDir || path.join(process.cwd(), `CSharpApp-${Date.now()}`);

  console.log(`📁 Creating ${projectType} project at: ${targetDir}`);

  // Check if dotnet CLI is available
  try {
    await execAsync('dotnet --version');
  } catch {
    throw new Error('.NET SDK not found. Please install .NET SDK from https://dotnet.microsoft.com/download');
  }

  // Create project using dotnet CLI
  const command = `dotnet new ${template} -f net${dotnetVersion} -o "${targetDir}"`;
  await execAsync(command);

Technical Analysis

The exported createProject() function constructs a shell command by directly interpolating the caller-controlled dotnetVersion and outputDir values. The resulting string is passed to execAsync(), which is a promisified version of child_process.exec and therefore executes the command through the operating-system shell.

The dotnetVersion value is not quoted or validated. An attacker can append shell metacharacters and an additional command. Although outputDir is enclosed in double quotes, an attacker can supply a double quote to terminate the argument and then inject shell syntax. Quoting without escaping or strict validation does not provide a security boundary.

The projectType value is effectively allowlisted through templateMap and falls back to console, so it is not the direct injection source. The vulnerable sources are dotnetVersion and outputDir.

At

...[truncated 1707 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace child_process.exec with child_process.execFile or child_process.spawn and supply each argument separately so no shell parses caller-controlled values:

    javascript
    const { execFile } = require('child_process');
    const { promisify } = require('util');
    
    const execFileAsync = promisify(execFile);
    
    await execFileAsync('dotnet', ['--version']);
    
    await execFileAsync('dotnet', [
      'new',
      template,
      '-f',
      `net${validatedVersion}`,
      '-o',
      targetDir,
    ]);
    
  2. Strictly allowlist supported .NET versions instead of accepting arbitrary strings. If flexible versions are required, enforce an exact format such as:

    javascript
    if (!/^\d+\.\d+$/.test(dotnetVersion)) {
      throw new Error('Unsupported .NET version');
    }
    

    An explicit set such as new Set(['6.0', '7.0', '8.0']) is preferable when supported versions are known.

  3. Resolve and normalize outputDir, reject NUL characters, and constrain the destination to an approved workspace when callers are not fully trusted:

    javascript
    const workspace = path.resolve(process.cwd());
    const targetDir = path.resolve(outputDir || path.join(
      workspace,
      `CSharpApp-${Date.now()}`
    ));
    
    if (targetDir !== workspace && !targetDir.startsWith(workspace + path.sep)) {
      throw new Error('Output directory must remain inside the workspace');
    }
    
  4. Execute the skill with least privilege and avoid exposing sensitive credentials to the process environment.

  5. Add automated tests containing shell metacharacters, quotes, command substitutions, newlines, and path traversal sequences to verify that inputs are rejected or treated strictly as literal arguments.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (4)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

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

md
# C# Developer Skill for OpenClaw

**鐗堟湰:** 1.0.0  
**鍒涘缓鏃堕棿:** 2026-03-27

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill description and usage guidance are written entirely in Chinese, and the argument hint and examples assume Chinese input without any opt-in or alternative language option. This can violate a language/locale policy when skills are expected to support user choice rather than implicitly forcing a specific language.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The fallback troubleshooting suggestions are hard-coded in Chinese, which imposes a specific language on users regardless of their preferences or locale. This is a natural-language policy issue because the skill does not offer language choice or document a justified locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The file includes a Chinese-language banner comment alongside English text, but there is no indication that multilingual output is optional or that the skill is specifically intended for a Chinese-speaking or region-specific environment. Under the language/locale policy, forcing or assuming a specific language without user opt-in can be a policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.