Back to skill

Security audit

OpenClaw TDD Assistant

Security checks for vulnerabilities and agentic risk

Overview

This TDD skill has a legitimate purpose, but it overstates what it can do and includes under-disclosed execution and dependency risks that users should review before installing.

Review before installing. Use this only in trusted repositories or an isolated environment, because its test and status commands can execute project code. Treat the advertised Jest, Go, mutation, and full TDD-cycle features as not actually shipped. Avoid shared or writable skill install locations where a sibling c-support directory could be modified, and do not rely on its /tmp-based report files for high-integrity automation.

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 (2)

T08 · Insecure Dependencies

Error
Location
scripts/generator.py:18
Finding

Unverified Sibling Directory Is Added to the Python Import Path

Content
View full analysis

Vulnerability Details

File Location: scripts/generator.py, lines 18-29
Vulnerability Type: Unsafe local dependency loading and Python path manipulation
Risk Level: High

Vulnerable Code

python
# Import C support library
c_support_path = Path(__file__).parent.parent.parent / 'c-support' / 'lib'
if c_support_path.exists():
    sys.path.insert(0, str(c_support_path))
    try:
        from c_parser import CParser
        from unity_templates import UnityTestGenerator, UnityCMakeTemplates
        C_SUPPORT_AVAILABLE = True
    except ImportError:
        C_SUPPORT_AVAILABLE = False
else:
    C_SUPPORT_AVAILABLE = False

Technical Analysis

The module constructs a path outside the Skill package, adds that directory to the beginning of sys.path, and imports modules from it based only on whether the directory exists. No package identity, ownership, integrity, or trusted-origin validation is performed.

Placing the directory at index zero gives modules in that directory precedence during import resolution. Importing c_parser and unity_templates executes their module-level Python code immediately. This occurs when generator.py is imported, even when the requested operation only concerns Python source code and does not require C support.

An attacker who can create or modify the expected sibling directory can therefore convert a normal test-generation invocation into arbitrary Python code execution. This represents an unsafe local dependency and supply-chain trust boundary.

Attack Path

  1. The attacker obtains write access to the directory containing the Skill's parent directory, a shared Skill installation, an extraction directory, or the existing c-support/lib directory.
  2. The attacker creates or modifies either:
    • c-support/lib/c_parser.py, or
    • c-support/lib/unity_templates.py.
  3. The malicious module includes arbitrary top-level Python code.
  4. A user or Agent invokes a generation command such as:
bash
py
...[truncated 970 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not prepend an implicitly trusted sibling directory to sys.path.
  2. Package C support as a normal, uniquely named Python package and install it through a controlled dependency mechanism.
  3. Pin the dependency to a reviewed version and verify its integrity through hashes, lock files, or signed release artifacts.
  4. Import C-specific dependencies lazily, only after confirming that the requested input is a C or header file.
  5. If local loading is unavoidable:
    • Resolve the expected path canonically.
    • Require it to remain under an explicitly configured trusted installation root.
    • Validate directory and file ownership and reject group- or world-writable locations.
    • Verify module hashes against a trusted manifest before import.
    • Avoid generic top-level module names such as c_parser.
  6. Execute optional parsers in a restricted subprocess if they may originate outside the core Skill package.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/runner.py:61
Finding

Predictable Shared Temporary Files Permit Report Spoofing and Cross-Process Interference

Content
View full analysis

Vulnerability Details

File Locations:

  • scripts/runner.py, lines 61-92
  • scripts/coverage.py, lines 20-48

Vulnerability Type: Unsafe predictable temporary files
Risk Level: Medium

Vulnerable Code

From scripts/runner.py:

python
cmd.append('-v' if verbose else '-q')
cmd.append('--tb=short')

# Try to get JSON output
cmd.append('--json-report')
cmd.append('--json-report-file=/tmp/pytest_report.json')

start_time = time.time()
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root)
elapsed = time.time() - start_time

# Parse results
passed = result.returncode == 0

# Parse output
output = result.stdout + result.stderr

# Extract test counts from output
passed_count = output.count(' PASSED')
failed_count = output.count(' FAILED')
error_count = output.count(' ERROR')
skipped_count = output.count(' SKIPPED')

# Try to read JSON report
try:
    json_report = Path('/tmp/pytest_report.json')
    if json_report.exists():
        report_data = json.loads(json_report.read_text())
        passed_count = report_data.get('summary', {}).get('passed', passed_count)
        failed_count = report_data.get('summary', {}).get('failed', failed_count)
except:
    pass

From scripts/coverage.py:

python
def run_coverage(self, source_dir: Optional[str] = None) -> Dict[str, Any]:
    """Run coverage analysis"""
    source = source_dir or 'src'

    # Run pytest with coverage
    cmd = [
        'python', '-m', 'pytest',
        '--cov=' + source,
        '--cov-report=term-missing',
        '--cov-report=json:/tmp/coverage.json',
        '-q'
    ]

    result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root)

    # Parse terminal output
    output = result.stdout + result.stderr

    # Extract coverage percentage
    coverage_match = re.search(r'TOTAL\s+\d+\s+\d+\s+(\d+)%', output)
    total_coverage = int(coverage_match.group(1)) if coverage_match else 0

    # Parse JSON report
    file_coverages = {}
    t
...[truncated 3138 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create a unique temporary directory for every invocation with tempfile.TemporaryDirectory().
  2. Store both report files inside that private directory and pass their generated paths to pytest.
  3. Read reports only after confirming that:
    • The subprocess completed.
    • The report exists.
    • The report is a regular file rather than a symbolic link.
    • Its modification time and expected schema correspond to the current run.
  4. Remove report files automatically when the invocation completes.
  5. Do not parse an existing report if pytest or the relevant reporting plugin failed.
  6. For concurrent execution, keep all report state scoped to the TestRunner or CoverageTracker instance rather than a global path.
  7. Replace the bare except in runner.py with explicit exceptions such as OSError and json.JSONDecodeError, and report invalid or stale results rather than silently accepting fallback behavior.
  8. Where supported, consume report data directly from a securely controlled subprocess stream instead of writing it to a shared filesystem location.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Claiming nonexistent generation, coverage, workflow, Jest, and Go functionality is a substantive integrity issue, not just a docs bug. In practice, it can mislead users into invoking shell or file-writing behavior in CI/CD or development environments under an inaccurate security and functionality model.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Claiming nonexistent generation, coverage, workflow, Jest, and Go functionality is a substantive integrity issue, not just a docs bug. In practice, it can mislead users into invoking shell or file-writing behavior in CI/CD or development environments under an inaccurate security and functionality model.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Claiming nonexistent generation, coverage, workflow, Jest, and Go functionality is a substantive integrity issue, not just a docs bug. In practice, it can mislead users into invoking shell or file-writing behavior in CI/CD or development environments under an inaccurate security and functionality model.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises commands that read project files, write generated tests, and invoke shell-based test runners, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege controls and can let a host agent expose broader filesystem or command execution capability than users expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file contains core usage instructions and feature descriptions in Chinese, while not indicating that the skill is region-specific or that users may choose another language. That creates a natural-language locale policy concern because the skill effectively forces one language without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The roadmap admits TDD cycle guidance is not implemented, yet the documentation presents it as available with concrete commands and output. That inconsistency can mislead users and automated systems into depending on nonexistent orchestration behavior, increasing the chance of unsafe or uncontrolled fallback actions.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The docs advertise a mutation-testing command and detailed behavior while the roadmap says mutation testing is not implemented. This can trigger failed automation or unexpected execution attempts in environments where shell access and code mutation are sensitive.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill claims Jest and Go support while the roadmap says JavaScript/Go support is not implemented. In a multi-language repository, this can cause improper routing of tasks, broken CI assumptions, and unnecessary granting of execution trust to a skill that cannot safely fulfill the request.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/coverage.py (reported line 34)May include surrounding context.

python
'-q'
        ]

        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root)

        # Parse terminal output
        output = result.stdout + result.stderr

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/runner.py (reported line 68)May include surrounding context.

python
'-q'
        ]

        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root)

        # Parse terminal output
        output = result.stdout + result.stderr

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/runner.py (reported line 122)May include surrounding context.

python
'-q'
        ]

        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.root)

        # Parse terminal output
        output = result.stdout + result.stderr

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/coverage.py (reported line 90)May include surrounding context.

python
'-q'
        ]

        result = subprocess.run(cmd, capture_output=True, cwd=self.root)

        if result.returncode in (0, 5):  # 5 = no tests collected
            output_path = self.root / output_dir / 'index.html'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Running pytest on a project executes repository-controlled Python code, including test modules, fixtures, plugins, and import-time side effects. In an agent skill context, this is especially dangerous because the tool may be used on untrusted repositories, enabling arbitrary code execution without any warning, consent gate, or sandboxing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Running unittest discovery executes project-controlled code and imports test modules from the target repository, which can trigger arbitrary code execution during import or test setup. Because this skill is specifically designed to automate test running, the context increases risk if it is pointed at untrusted codebases without a safety notice or isolation boundary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The skill manifest says the TDD assistant supports pytest, unittest, jest, and go test, but this file's top-level documentation and implementation only generate tests for Python and C/Unity. This is a semantic mismatch between the advertised scope and what the code in this file actually implements.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.