Skill: ithacajason/jasonlai-security-audit (version 1.0.0)

--- name: security-audit description: "Security audit for external resources (GitHub repos, downloaded skills, files). Detects malicious code, suspicious executables, and content mismatches. Use when: (1) cloning GitHub projects, (2) downloading skills from web, (3) running external code/scripts. Always run before trusting or executing external code." metadata: { "openclaw": { "emoji": "🛡️", "requires": { "bins": ["python3"], "python": [">=3.8"] }, "install": [ { "id": "default", "kind": "none", "label": "Python 3.8+ required (usually pre-installed)", }, ], }, } --- # Security Audit Skill Automated security checks for external resources before execution. ## When to Use ✅ **ALWAYS use this skill when:** - Cloning any GitHub repository - Downloading skills or code from the web - Running external scripts or code - Installing new tools from untrusted sources ## Security Checks ### File Type Detection | File Type | Risk Level | Action | |------------|-------------|--------| | `.py`, `.js`, `.ts`, `.go`, `.rs` | ✅ Low | Safe to review | | `.md`, `.txt`, `.json`, `.yaml` | ✅ Low | Safe to read | | `.exe`, `.bat`, `.sh`, `.app`, `.msi` | 🔴 High | Block without review | | Unknown binary files | 🔴 High | Block without review | ### Content Analysis - **Source Code Present**: ✅ Pass - **README Matches Content**: ✅ Pass - **Suspicious Patterns**: Detects: - Base64 encoded payloads - Shellcode signatures - Obfuscated code - Network connections in scripts ### Red Flags 🚨 **Immediately alert user if:** - Executable files without source code - README claims functionality not present in code - Extremely long text files (> 50KB with single line) - Encrypted/obfuscated content - Direct download links in README (not GitHub releases) ## Usage ```bash # Audit a directory cd /path/to/repo python3 audit.py # Audit with verbose output python3 audit.py --verbose # Export report to file python3 audit.py --output report.txt ``` ## Check Results ### ✅ Safe ``` 🛡️ Security Audit: PASSED All checks passed. This resource appears safe to use. - Source code: Found - File types: Normal - Content: Matches description - No suspicious patterns detected ``` ### ⚠️ Warning ``` ⚠️ Security Audit: WARNING Found minor issues that need review: - Long line in file.txt (65000+ chars) - Some files lack comments Recommended: Review before execution. ``` ### 🚨 Critical ``` 🚨 Security Audit: BLOCKED Critical security issues detected: - Executable file: resolver.exe (NO source code) - Suspicious payload: icon16.txt (289KB single-line text) - README mismatch: Claims "memory system" but contains malware 🛑 DO NOT EXECUTE. Delete immediately. ``` ## Integration with OpenClaw This skill can be invoked automatically by OpenClaw when: 1. **Cloning Repos**: Runs after `git clone` 2. **Downloading Skills**: Runs after `clawhub install` 3. **Running External Scripts**: Runs before execution To enable automatic auditing, add to your workflow: ```bash # After git clone git clone <repo-url> && cd <repo> && python3 audit.py # After clawhub install clawhub install <skill> && python3 ~/.clawhub/skills/<skill>/audit.py ``` ## Security Best Practices ### For Users 1. **Never run** unverified executables 2. **Always review** code before execution 3. **Check file types** in downloaded archives 4. **Verify repository** activity and contributors 5. **Use virtual environments** for testing ### For Skill Authors 1. **Provide source code** in clear text 2. **Include README** that matches functionality 3. **Avoid obfuscation** or encryption 4. **Document dependencies** clearly 5. **Use standard formats** (no custom binaries) ## False Positives Some safe projects may trigger warnings: - **Large data files**: Legitimate models, datasets - **Minified code**: Production JavaScript/CSS - **Compiled modules**: Native Python extensions **Review manually** before deciding to block. ## Reference Cases ### ClawIntelligentMemory (2026-03-03) ``` 🚨 BLOCKED: Malware disguised as OpenClaw memory system Evidence: - resolver.exe (Windows PE executable, no source) - icon16.txt (289KB single-line,疑似 shellcode) - App.bat (launches resolver.exe with payload) - README claims "memory system", actual content is malware Action: Deleted immediately ``` ## Notes - This is a **basic heuristic** check, not a full antivirus - Always use human judgment for final decisions - Report false positives to improve detection - Keep this skill updated with new threat patterns

path: README.md
content: # 🛡️ OpenClaw Security Audit Skill

Automatic security checking for external resources before execution.

## Overview

This skill provides automated security audits for:
- GitHub repositories cloned locally
- Skills downloaded from the web
- External scripts and code
- Any untrusted code before execution

## Why This Matters

Malicious actors often disguise malware as legitimate software:
- Fake "tools" that contain trojans
- README claims that don't match actual code
- Executables bundled with suspicious payloads
- Shellcode hidden in text files

This skill catches these patterns **before** you run them.

## Features

### 🔍 File Type Detection
- Identifies high-risk executables (.exe, .bat, .sh, .app)
- Recognizes safe source code (Python, JavaScript, Rust, etc.)
- Flags unknown binary files

### 📄 Content Analysis
- Detects suspicious patterns (base64, shellcode, obfuscation)
- Checks for extremely long single-line files (shellcode payloads)
- Validates README descriptions match actual code

### 🚨 Risk Scoring
- **CRITICAL**: Block immediately - likely malware
- **WARNING**: Review manually - suspicious but not clearly malicious
- **SAFE**: No concerns - normal project structure

## Quick Start

### 1. Install

```bash
# Copy to your skills directory
cp -r security-audit ~/.nvm/versions/node/v22.16.0/lib/node_modules/openclaw/skills/

# Make script executable
chmod +x ~/.nvm/versions/node/v22.16.0/lib/node_modules/openclaw/skills/security-audit/audit.py
```

### 2. Use

```bash
# Audit current directory
python3 audit.py

# Audit with verbose output
python3 audit.py --verbose

# Save report to file
python3 audit.py --output report.txt
```

### 3. Automatic Integration

Add to your workflow after git clone:

```bash
git clone https://github.com/user/repo.git && \
cd repo && \
python3 /path/to/audit.py
```

## Security Checks

### High-Risk File Types

| Extension | Risk | Example |
|-----------|-------|---------|
| `.exe`, `.bat`, `.cmd` | 🔴 Critical | Windows malware |
| `.sh`, `.ps1`, `.vbs` | 🔴 Critical | Script malware |
| `.app`, `.dmg`, `.pkg` | 🔴 Critical | macOS trojans |
| `.dll`, `.so`, `.dylib` | 🔴 Critical | Malicious libraries |

### Safe Source Code

✅ These are safe to review:
- `.py` (Python)
- `.js`, `.ts` (JavaScript/TypeScript)
- `.go` (Go)
- `.rs` (Rust)
- `.java`, `.c`, `.cpp` (Compiled languages)

### Suspicious Patterns

Detects:
- Long base64 strings (>100 chars)
- Shellcode signatures
- `eval()` and `exec()` with long payloads
- Dynamic imports from untrusted sources
- Malware keywords

## Output Examples

### ✅ Safe Project

```
🔍 Scanning: /path/to/project

🛡️ Security Audit: PASSED
==================================================

📊 Summary:
   Total files scanned: 15
   Source code files: 8
   High-risk files: 0
   Suspicious patterns: 0

✅ Source Code Found:
   - main.py
   - utils.js
   - Cargo.toml
   ... and 5 more

==================================================

✅ Safe to Use
Recommendation: No immediate concerns
```

### 🚨 Malware Detected

```
🔍 Scanning: /path/to/suspicious-repo

🚨 Security Audit: BLOCKED
==================================================

📊 Summary:
   Total files scanned: 4
   Source code files: 0
   High-risk files: 1
   Suspicious patterns: 2

🚨 High-Risk Files (Executable):
   - /path/to/suspicious-repo/resolver.exe

🚨 Large Single-Line Files (Potential Shellcode):
   - /path/to/suspicious-repo/icon16.txt

⚠️ Suspicious Patterns Found:
   Pattern: shellcode
     - /path/to/suspicious-repo/icon16.txt:1
   Pattern: [a-zA-Z0-9+/]{100,}={0,2}
     - /path/to/suspicious-repo/icon16.txt:1

🚨 README Mismatch: Claims AI/memory features but no source code found

==================================================

🛑 DO NOT EXECUTE
Recommendation: Delete immediately - this appears to be malware
```

## Real-World Examples

### ClawIntelligentMemory (2026-03-03)

**Claimed**: OpenClaw three-layer memory system

**Actual**: Windows malware

```
🚨 BLOCKED: Malware disguised as OpenClaw memory system

Evidence:
- resolver.exe (Windows PE executable, no source)
- icon16.txt (289KB single-line,疑似 shellcode)
- App.bat (launches resolver.exe with payload)
- README claims "memory system", actual content is malware
```

**Action**: Deleted immediately

## Best Practices

### For Users

1. **Always audit** before running external code
2. **Never trust** executables without source code
3. **Review source** even if audit passes
4. **Use virtual environments** for testing
5. **Check repository** activity and contributors

### For Skill Authors

1. **Provide source code** in clear text
2. **Include accurate README** descriptions
3. **Avoid obfuscation** or minification
4. **Document dependencies** clearly
5. **Use standard file formats**

## Limitations

- **Heuristic-based**: Not a full antivirus replacement
- **False positives**: Large datasets, minified code
- **No runtime analysis**: Only static code analysis
- **Manual review needed**: Final decision requires human judgment

## Contributing

To improve detection:

1. Add new suspicious patterns to `SUSPICIOUS_PATTERNS`
2. Add high-risk extensions to `HIGH_RISK_EXTENSIONS`
3. Tune thresholds in `check_single_line_large_file()`
4. Report false positives to improve heuristics

## License

MIT License - Free to use and modify

## Support

For questions or issues:
- Check `SKILL.md` for detailed usage
- Report bugs to your OpenClaw configuration
- Update patterns for new threats


path: audit.py
content: #!/usr/bin/env python3
"""
OpenClaw Security Audit Script
Automated security checks for external resources before execution.
"""

import os
import sys
import re
import argparse
from pathlib import Path
from typing import List, Dict, Tuple

# ANSI color codes for terminal output
COLORS = {
    'GREEN': '\033[92m',
    'YELLOW': '\033[93m',
    'RED': '\033[91m',
    'BLUE': '\033[94m',
    'RESET': '\033[0m',
}

# High-risk file extensions
HIGH_RISK_EXTENSIONS = {
    '.exe', '.bat', '.cmd', '.msi', '.app', '.dmg',
    '.pkg', '.deb', '.rpm', '.sh', '.ps1', '.vbs',
    '.dll', '.so', '.dylib', '.bin'
}

# Safe source code extensions
SAFE_EXTENSIONS = {
    '.py', '.js', '.ts', '.tsx', '.jsx', '.go', '.rs',
    '.java', '.c', '.cpp', '.h', '.hpp', '.php', '.rb',
    '.swift', '.kt', '.dart', '.lua', '.r', '.m'
}

# Suspicious patterns in text files
SUSPICIOUS_PATTERNS = [
    r'base64\s*\([^)]{100,}\)',  # Long base64 strings
    r'[a-zA-Z0-9+/]{100,}={0,2}',  # Base64-like strings
    r'eval\s*\([^)]+\)',  # eval() usage
    r'exec\s*\([^)]+\)',  # exec() usage
    r'__import__\s*\(\s*[\'""][^\'"]+[\'"]\s*\)',  # Dynamic imports
    r'shellcode',  # Shellcode keyword
    r'malware|virus|trojan|backdoor',  # Malware keywords
]


def color_print(text: str, color: str = 'RESET'):
    """Print colored text to terminal."""
    if sys.stdout.isatty():
        print(f"{COLORS.get(color, '')}{text}{COLORS['RESET']}")
    else:
        print(text)


def get_file_extension(filepath: Path) -> str:
    """Get file extension in lowercase."""
    return filepath.suffix.lower()


def is_high_risk_file(filepath: Path) -> bool:
    """Check if file is high-risk type."""
    ext = get_file_extension(filepath)
    return ext in HIGH_RISK_EXTENSIONS


def is_safe_source_file(filepath: Path) -> bool:
    """Check if file is safe source code."""
    ext = get_file_extension(filepath)
    return ext in SAFE_EXTENSIONS


def is_text_file(filepath: Path) -> bool:
    """Check if file is text type by reading first bytes."""
    try:
        with open(filepath, 'rb') as f:
            chunk = f.read(1024)
            # Check for null bytes (binary indicator)
            if b'\x00' in chunk:
                return False
            # Try to decode as UTF-8
            chunk.decode('utf-8')
            return True
    except (UnicodeDecodeError, IOError):
        return False


def scan_text_file(filepath: Path) -> Dict[str, List[int]]:
    """Scan text file for suspicious patterns."""
    results = {pattern: [] for pattern in SUSPICIOUS_PATTERNS}
    
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            for line_num, line in enumerate(f, 1):
                # Remove Python comments and string literals to reduce false positives
                cleaned_line = line
                # Remove single-line comments
                cleaned_line = re.sub(r'#.*$', '', cleaned_line)
                # Remove multi-line strings (Python triple quotes)
                cleaned_line = re.sub(r'"""[\s\S]*?"""', '', cleaned_line)
                cleaned_line = re.sub(r"'''[\s\S]*?'''", '', cleaned_line)
                # Remove regular string literals
                cleaned_line = re.sub(r'"[^"]*"', '', cleaned_line)
                cleaned_line = re.sub(r"'[^']*'", '', cleaned_line)
                
                for pattern in SUSPICIOUS_PATTERNS:
                    if re.search(pattern, cleaned_line, re.IGNORECASE):
                        results[pattern].append(line_num)
    except Exception as e:
        pass
    
    return results


def check_single_line_large_file(filepath: Path) -> bool:
    """Check if file has extremely long single line (potential shellcode)."""
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            for line in f:
                if len(line) > 50000:  # Threshold: 50KB single line
                    return True
    except Exception:
        pass
    return False


def check_readme_mismatch(directory: Path) -> Tuple[bool, str]:
    """Check if README description matches actual content."""
    readme_files = list(directory.glob('README*')) + list(directory.glob('readme*'))
    
    if not readme_files:
        return False, "No README found"
    
    readme_path = readme_files[0]
    
    try:
        with open(readme_path, 'r', encoding='utf-8', errors='ignore') as f:
            readme_content = f.read().lower()
    except Exception:
        return False, "Cannot read README"
    
    # Check for suspicious claims vs actual files
    has_source_code = any(
        is_safe_source_file(f)
        for f in directory.rglob('*')
        if f.is_file()
    )
    
    # Check for direct download links in README
    if '.zip' in readme_content and 'raw.githubusercontent' in readme_content:
        return True, "README contains direct download links (suspicious)"
    
    # Check for memory/AI claims without actual AI code
    memory_keywords = ['memory', 'ai', 'intelligence', 'three-layer', '三层']
    if any(keyword in readme_content for keyword in memory_keywords):
        if not has_source_code:
            return True, "Claims AI/memory features but no source code found"
    
    return False, "OK"


def scan_directory(directory: Path, verbose: bool = False) -> Dict:
    """Scan directory for security issues."""
    results = {
        'high_risk_files': [],
        'source_files': [],
        'suspicious_patterns': {},
        'large_single_line_files': [],
        'readme_mismatch': False,
        'readme_msg': '',
        'total_files': 0,
    }
    
    for filepath in directory.rglob('*'):
        if not filepath.is_file():
            continue
        
        results['total_files'] += 1
        
        # Check file type
        if is_high_risk_file(filepath):
            results['high_risk_files'].append(str(filepath))
            if verbose:
                color_print(f"⚠️  High-risk file: {filepath}", 'YELLOW')
        
        elif is_safe_source_file(filepath):
            results['source_files'].append(str(filepath))
            if verbose:
                color_print(f"✅ Source file: {filepath}", 'GREEN')
        
        # Check text files
        if is_text_file(filepath):
            # Check for large single line
            if check_single_line_large_file(filepath):
                results['large_single_line_files'].append(str(filepath))
                if verbose:
                    color_print(f"🚨 Large single-line file: {filepath}", 'RED')
            
            # Scan for suspicious patterns
            suspicious = scan_text_file(filepath)
            for pattern, lines in suspicious.items():
                if lines:
                    if pattern not in results['suspicious_patterns']:
                        results['suspicious_patterns'][pattern] = []
                    results['suspicious_patterns'][pattern].extend(
                        [f"{filepath}:{line}" for line in lines]
                    )
                    if verbose:
                        color_print(f"⚠️  Suspicious pattern in {filepath} (line {lines[0]})", 'YELLOW')
    
    # Check README
    mismatch, msg = check_readme_mismatch(directory)
    results['readme_mismatch'] = mismatch
    results['readme_msg'] = msg
    
    return results


def calculate_risk_level(results: Dict) -> str:
    """Calculate overall risk level."""
    critical_score = 0
    
    # High-risk executables without source code
    if results['high_risk_files'] and not results['source_files']:
        critical_score += 3
    
    # Large single-line files (potential shellcode)
    if results['large_single_line_files']:
        critical_score += 3
    
    # README mismatch
    if results['readme_mismatch']:
        critical_score += 2
    
    # Suspicious patterns
    if results['suspicious_patterns']:
        critical_score += len(results['suspicious_patterns'])
    
    if critical_score >= 5:
        return 'CRITICAL'
    elif critical_score >= 2:
        return 'WARNING'
    else:
        return 'SAFE'


def print_report(results: Dict, output_file: str = None):
    """Print security audit report."""
    risk_level = calculate_risk_level(results)
    
    # Header
    if risk_level == 'CRITICAL':
        color_print("\n🚨 Security Audit: BLOCKED", 'RED')
    elif risk_level == 'WARNING':
        color_print("\n⚠️  Security Audit: WARNING", 'YELLOW')
    else:
        color_print("\n🛡️ Security Audit: PASSED", 'GREEN')
    
    color_print("=" * 50, 'BLUE')
    
    # Summary
    print(f"\n📊 Summary:")
    print(f"   Total files scanned: {results['total_files']}")
    print(f"   Source code files: {len(results['source_files'])}")
    print(f"   High-risk files: {len(results['high_risk_files'])}")
    print(f"   Suspicious patterns: {sum(len(v) for v in results['suspicious_patterns'].values())}")
    
    # Detailed findings
    if results['high_risk_files']:
        color_print("\n🚨 High-Risk Files (Executable):", 'RED')
        for f in results['high_risk_files']:
            color_print(f"   - {f}", 'RED')
    
    if results['source_files'] and not results['high_risk_files']:
        color_print("\n✅ Source Code Found:", 'GREEN')
        for f in results['source_files'][:5]:
            color_print(f"   - {f}", 'GREEN')
        if len(results['source_files']) > 5:
            print(f"   ... and {len(results['source_files']) - 5} more")
    
    if results['large_single_line_files']:
        color_print("\n🚨 Large Single-Line Files (Potential Shellcode):", 'RED')
        for f in results['large_single_line_files']:
            color_print(f"   - {f}", 'RED')
    
    if results['suspicious_patterns']:
        color_print("\n⚠️  Suspicious Patterns Found:", 'YELLOW')
        for pattern, locations in results['suspicious_patterns'].items():
            print(f"   Pattern: {pattern}")
            for loc in locations[:3]:
                color_print(f"     - {loc}", 'YELLOW')
            if len(locations) > 3:
                print(f"     ... and {len(locations) - 3} more")
    
    if results['readme_mismatch']:
        color_print(f"\n🚨 README Mismatch: {results['readme_msg']}", 'RED')
    
    # Recommendation
    color_print("\n" + "=" * 50, 'BLUE')
    if risk_level == 'CRITICAL':
        color_print("\n🛑 DO NOT EXECUTE", 'RED')
        color_print("Recommendation: Delete immediately - this appears to be malware", 'RED')
    elif risk_level == 'WARNING':
        color_print("\n⚠️ Review Before Execution", 'YELLOW')
        color_print("Recommendation: Manual review required", 'YELLOW')
    else:
        color_print("\n✅ Safe to Use", 'GREEN')
        color_print("Recommendation: No immediate concerns", 'GREEN')
    
    print()
    
    # Save to file if requested
    if output_file:
        with open(output_file, 'w') as f:
            f.write(f"Security Audit Report\n")
            f.write(f"Risk Level: {risk_level}\n")
            f.write(f"Total Files: {results['total_files']}\n")
            f.write(f"\nDetails:\n{results}\n")


def main():
    parser = argparse.ArgumentParser(
        description='Security audit for external resources'
    )
    parser.add_argument(
        'directory',
        nargs='?',
        default='.',
        help='Directory to scan (default: current directory)'
    )
    parser.add_argument(
        '-v', '--verbose',
        action='store_true',
        help='Show detailed output during scan'
    )
    parser.add_argument(
        '-o', '--output',
        help='Save report to file'
    )
    
    args = parser.parse_args()
    
    directory = Path(args.directory).resolve()
    
    if not directory.exists():
        color_print(f"❌ Directory not found: {directory}", 'RED')
        sys.exit(1)
    
    color_print(f"🔍 Scanning: {directory}", 'BLUE')
    print()
    
    results = scan_directory(directory, verbose=args.verbose)
    print_report(results, output_file=args.output)


if __name__ == '__main__':
    main()


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: clean (LOW)