Back to skills
SkillHub ClubShip Full StackFull Stack

openscan

Scan binaries and scripts for malicious patterns before trusting them. Use when installing skills, evaluating unknown binaries, or auditing tool dependencies.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,129
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B84.0

Install command

npx @skill-hub/cli install openclaw-skills-openscan

Repository

openclaw/skills

Skill path: skills/dev-null321/openscan

Scan binaries and scripts for malicious patterns before trusting them. Use when installing skills, evaluating unknown binaries, or auditing tool dependencies.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install openscan into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding openscan to shared team environments
  • Use openscan for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: openscan
description: Scan binaries and scripts for malicious patterns before trusting them. Use when installing skills, evaluating unknown binaries, or auditing tool dependencies.
version: 1.0.0
author: Marq Britt
homepage: https://github.com/marqbritt/openscan
metadata:
  openclaw:
    emoji: "πŸ›‘οΈ"
    requires:
      node: ">=18"
    platforms:
      - darwin
      - linux
---

# OpenScan

Lightweight malware detection for macOS and Linux binaries/scripts. Ported from the Harkonnen antimalware engine.

## What It Detects

**Binary Analysis:**
- Mach-O (macOS) and ELF (Linux) parsing
- Suspicious dylibs/shared objects (Frida, injection frameworks)
- Missing/invalid code signatures (macOS)
- Disabled security features (PIE, NX, RELRO)
- Packed/encrypted binaries (high entropy)

**Pattern Detection:**
- Shellcode byte sequences
- Suspicious API references (process injection, keylogging, etc.)
- Network indicators (embedded URLs, IPs)
- Encoded payloads (base64 blobs)

**Script Analysis:**
- Dangerous shell patterns (curl|bash, eval, etc.)
- Obfuscation indicators
- Privilege escalation attempts

## Usage

```bash
# Scan a single binary
node bin/scan.js /path/to/binary

# Scan a skill folder
node bin/scan.js /path/to/skill-folder

# JSON output for automation
node bin/scan.js /path --json

# Only show threats
node bin/scan.js /path --quiet
```

## Exit Codes

- `0` - Clean (score ≀ 20)
- `1` - Suspicious (score 21-60)
- `2` - High threat (score > 60)

## Threat Scoring

Each file receives a score from 0-100:

| Score | Level    | Meaning                              |
|-------|----------|--------------------------------------|
| 0-20  | CLEAN    | No significant findings              |
| 21-40 | LOW      | Minor concerns, probably safe        |
| 41-60 | MEDIUM   | Suspicious patterns, review manually |
| 61-80 | HIGH     | Likely malicious or dangerous        |
| 81-100| CRITICAL | Known malicious patterns             |

## Integration with OpenClaw

Use before installing or trusting unknown binaries:

```javascript
// Example: scan before allowing a skill's binary
const { scanFile } = require('openscan/lib/scanner');

async function checkBinary(binPath) {
  const result = await scanFile(binPath);
  if (result.threatScore > 40) {
    throw new Error(`Binary failed security scan: ${result.findings.join(', ')}`);
  }
  return true;
}
```

## Limitations

- Not a replacement for full antivirus
- Signature-based detection is minimal (no hash database)
- May produce false positives on legitimate security tools
- Cannot detect all obfuscation techniques

## Credits

Detection logic ported from [Harkonnen](https://github.com/dev-null321/Harkonnen) antimalware engine.


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### bin/scan.js

```javascript
#!/usr/bin/env node
/**
 * OpenScan CLI
 * Scan binaries and scripts for malicious patterns
 */

const fs = require('fs');
const path = require('path');
const { scanFile, scanDirectory, formatResult } = require('../lib/scanner');

const VERSION = '1.0.0';

function printHelp() {
  console.log(`
OpenScan v${VERSION}
Scan binaries and scripts for malicious patterns.

Usage:
  scan <path> [options]

Options:
  --json          Output results as JSON
  --quiet         Only output threats (score > 20)
  --no-color      Disable colored output
  --max-size=N    Max file size in MB (default: 50)
  --help          Show this help
  --version       Show version

Examples:
  scan /usr/local/bin/some-binary
  scan ./my-skill --json
  scan /path/to/file --quiet
`);
}

async function main() {
  const args = process.argv.slice(2);
  
  if (args.includes('--help') || args.includes('-h')) {
    printHelp();
    process.exit(0);
  }

  if (args.includes('--version') || args.includes('-v')) {
    console.log(VERSION);
    process.exit(0);
  }

  // Parse options
  const options = {
    json: args.includes('--json'),
    quiet: args.includes('--quiet'),
    noColor: args.includes('--no-color')
  };

  const maxSizeArg = args.find(a => a.startsWith('--max-size='));
  if (maxSizeArg) {
    options.maxSize = parseInt(maxSizeArg.split('=')[1], 10) * 1024 * 1024;
  }

  // Get target path
  const targetPath = args.find(a => !a.startsWith('--'));
  
  if (!targetPath) {
    console.error('Error: No path specified');
    printHelp();
    process.exit(1);
  }

  const fullPath = path.resolve(targetPath);

  if (!fs.existsSync(fullPath)) {
    console.error(`Error: Path not found: ${fullPath}`);
    process.exit(1);
  }

  const stats = fs.statSync(fullPath);
  let results;

  if (stats.isDirectory()) {
    if (!options.json) {
      console.log(`Scanning directory: ${fullPath}\n`);
    }
    results = await scanDirectory(fullPath, options);
  } else {
    results = [await scanFile(fullPath, options)];
  }

  // Filter if quiet mode
  if (options.quiet) {
    results = results.filter(r => r.threatScore > 20);
  }

  // Output
  if (options.json) {
    console.log(JSON.stringify(results, null, 2));
  } else {
    let threatCount = 0;
    let highThreatCount = 0;

    for (const result of results) {
      console.log(formatResult(result, options));
      if (result.threatScore > 20) threatCount++;
      if (result.threatScore > 60) highThreatCount++;
    }

    console.log('\n' + '='.repeat(50));
    console.log(`Scanned: ${results.length} file(s)`);
    console.log(`Threats: ${threatCount} suspicious, ${highThreatCount} high-risk`);
    console.log('='.repeat(50));
  }

  // Exit code based on findings
  const maxScore = Math.max(...results.map(r => r.threatScore), 0);
  if (maxScore > 60) {
    process.exit(2); // High threat
  } else if (maxScore > 20) {
    process.exit(1); // Suspicious
  }
  process.exit(0); // Clean
}

main().catch(err => {
  console.error('Error:', err.message);
  process.exit(1);
});

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### README.md

```markdown
# OpenScan

A lightweight malware detection library for OpenClaw, targeting macOS and Linux binaries and scripts. Ported from the [Harkonnen](https://github.com/dev-null321/Harkonnen) antimalware engine.

## Why This Exists

OpenClaw skills can declare binary dependencies via `requires.bins`. Users install these binaries from various sources (Homebrew, npm, apt, random GitHub releases). There's currently no verification that these binaries are safe.

This scanner provides:
- **Pre-trust scanning** of binaries before execution
- **Skill folder auditing** to catch malicious scripts
- **Programmatic API** for integration into OpenClaw's skill loading

## Features

### Binary Analysis

| Platform | Format | Detection |
|----------|--------|-----------|
| macOS | Mach-O (32/64-bit, Universal/FAT) | Suspicious dylibs, code signature, encryption, security flags |
| Linux | ELF (32/64-bit) | Suspicious shared objects, security features (PIE, NX, RELRO) |

**What it checks:**
- **Suspicious libraries**: Frida, Cynject, MobileSubstrate, injection frameworks
- **Code signatures**: Missing or invalid signatures (macOS)
- **Security features**: ASLR/PIE disabled, executable stack/heap, missing NX
- **Packing/encryption**: High entropy detection, encrypted segments
- **Segment anomalies**: Suspicious names like `__INJECT`, `UPX`, `__MALWARE`

### Pattern Detection

Scans binary content for:
- **Shellcode patterns**: x86/x64 prologue sequences, NOP sleds, infinite loops
- **Suspicious APIs**: Process injection (CreateRemoteThread, VirtualAllocEx), keylogging (GetAsyncKeyState), anti-debugging (IsDebuggerPresent)
- **Network indicators**: Embedded URLs, IP addresses
- **Encoded payloads**: Large base64 blobs

### Script Analysis

For shell scripts, Python, JavaScript, etc.:
- **Dangerous patterns**: `curl | bash`, `eval()`, base64 decode + exec
- **Persistence mechanisms**: crontab, launchctl, LaunchAgents
- **Injection vectors**: `LD_PRELOAD`, `DYLD_INSERT_LIBRARIES`
- **Obfuscation**: Heavy hex escaping, very long lines

## Installation

```bash
# Clone the repo
git clone https://github.com/marqbritt/openscan.git
cd openscan

# No dependencies - pure Node.js
node bin/scan.js --help
```

Or install globally:
```bash
npm install -g .
openclaw-scan --help
```

## Usage

### Command Line

```bash
# Scan a single binary
node bin/scan.js /usr/local/bin/some-tool

# Scan a skill folder
node bin/scan.js ~/.openclaw/skills/some-skill

# JSON output (for automation)
node bin/scan.js /path/to/binary --json

# Only show threats (score > 20)
node bin/scan.js /path/to/folder --quiet

# Disable colors (for logging)
node bin/scan.js /path --no-color
```

### Programmatic API

```javascript
const { scanFile, scanDirectory, formatResult } = require('openscan');

// Scan a single file
async function checkBinary(path) {
  const result = await scanFile(path);
  
  console.log(`${result.name}: ${result.threatLevel} (${result.threatScore}/100)`);
  
  if (result.threatScore > 40) {
    console.log('Findings:', result.findings);
    return false; // Don't trust
  }
  return true;
}

// Scan an entire skill folder
async function auditSkill(skillPath) {
  const results = await scanDirectory(skillPath);
  
  const threats = results.filter(r => r.threatScore > 20);
  if (threats.length > 0) {
    console.log(`Found ${threats.length} suspicious files:`);
    threats.forEach(r => console.log(formatResult(r)));
  }
  
  return threats.length === 0;
}
```

### Integration Examples

**Pre-install hook (conceptual):**
```javascript
// In OpenClaw's skill loader
async function loadSkill(skillPath) {
  const meta = parseSkillMeta(skillPath);
  
  if (meta.requires?.bins) {
    for (const bin of meta.requires.bins) {
      const binPath = which(bin);
      if (binPath) {
        const result = await scanFile(binPath);
        if (result.threatScore > 60) {
          throw new Error(`Binary ${bin} failed security scan: ${result.findings.join(', ')}`);
        }
      }
    }
  }
  
  // Continue loading...
}
```

**Agent self-check:**
```javascript
// Before recommending a tool to the user
const { scanFile } = require('openscan');

async function recommendTool(toolPath) {
  const result = await scanFile(toolPath);
  
  if (result.threatScore > 40) {
    return `⚠️ Warning: ${toolPath} has suspicious characteristics:\n${result.findings.join('\n')}`;
  }
  
  return `βœ“ ${toolPath} appears safe (score: ${result.threatScore}/100)`;
}
```

## Threat Scoring

Each file receives a score from 0-100 based on weighted findings:

| Score | Level | Color | Meaning |
|-------|-------|-------|---------|
| 0-20 | CLEAN | Green | No significant findings |
| 21-40 | LOW | Yellow | Minor concerns, probably safe |
| 41-60 | MEDIUM | Orange | Suspicious patterns, review manually |
| 61-80 | HIGH | Red | Likely malicious or dangerous |
| 81-100 | CRITICAL | Purple | Known malicious patterns |

**Scoring weights:**
- Suspicious dylib/library: +15 per finding
- Missing code signature: +10 (macOS)
- High entropy (>7.5): +25
- Shellcode pattern: +20 per pattern
- Suspicious API reference: +5 per API (max 30)
- Dangerous script pattern: +10 per pattern
- Security features disabled: +5-15 depending on feature

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Clean (max score ≀ 20) |
| 1 | Suspicious (max score 21-60) |
| 2 | High threat (max score > 60) |

## Output Format

### Human-readable (default)

```
[CLEAN] ls
  Path: /bin/ls
  Type: macho | Size: 151.0KB
  Score: 12/100
  SHA256: 03a229a30505d148f4a66f3eaa1d046d7f6e7e4c2b7abd8f4cf0e3ac2b124651
  Findings:
    - Suspicious API: exec
    - Found 4 URL(s)
```

### JSON (--json)

```json
{
  "path": "/bin/ls",
  "name": "ls",
  "exists": true,
  "size": 154624,
  "type": "macho",
  "hashes": {
    "md5": "...",
    "sha256": "..."
  },
  "threatScore": 12,
  "threatLevel": "CLEAN",
  "findings": [
    "Suspicious API: exec",
    "Found 4 URL(s)"
  ],
  "details": {
    "binary": { ... },
    "patterns": { ... },
    "packing": { ... }
  }
}
```

## Architecture

```
lib/
β”œβ”€β”€ entropy.js    # Shannon entropy calculation
β”‚                 # - calculateEntropy(buffer) β†’ 0-8
β”‚                 # - detectPacking(buffer) β†’ {isPacked, entropy, regions}
β”‚
β”œβ”€β”€ macho.js      # Mach-O parser (macOS)
β”‚                 # - parseMachO(buffer) β†’ {segments, dylibs, flags, ...}
β”‚                 # - Handles FAT/Universal binaries
β”‚                 # - Code signature detection
β”‚
β”œβ”€β”€ elf.js        # ELF parser (Linux)
β”‚                 # - parseELF(buffer) β†’ {sections, libs, flags, ...}
β”‚                 # - Security feature detection (PIE, NX, RELRO)
β”‚
β”œβ”€β”€ patterns.js   # Pattern detection
β”‚                 # - scanPatterns(buffer) β†’ {shellcode, apis, urls, ...}
β”‚                 # - Shellcode byte sequences
β”‚                 # - API string references
β”‚
└── scanner.js    # Main orchestrator
                  # - scanFile(path) β†’ result
                  # - scanDirectory(path) β†’ results[]
                  # - Threat scoring and formatting
```

## Limitations

1. **Not a replacement for antivirus/EDR** - This is lightweight static analysis, not a full security product.

2. **No signature database** - Does not check file hashes against known malware databases. Could integrate VirusTotal API in the future.

3. **Static analysis only** - Cannot detect runtime-only malicious behavior. No sandboxing or dynamic analysis.

4. **False positives** - Security tools, debuggers, and legitimate system utilities may trigger findings.

5. **Obfuscation** - Sophisticated obfuscation or custom packers may evade detection.

## Future Enhancements

- [ ] VirusTotal API integration for hash lookups
- [ ] Local blocklist of known-bad hashes
- [ ] npm package audit integration
- [ ] Homebrew formula verification
- [ ] OpenClaw core integration (pre-load hooks)
- [ ] ClawHub server-side scanning

## Credits

Detection logic ported from [Harkonnen](https://github.com/dev-null321/Harkonnen) antimalware engine by dev-null321.

## License

MIT

```

### _meta.json

```json
{
  "owner": "dev-null321",
  "slug": "openscan",
  "displayName": "OpenScan",
  "latest": {
    "version": "1.0.0",
    "publishedAt": 1770504942370,
    "commit": "https://github.com/openclaw/skills/commit/bdb029c409880dc41eb5405fa13733ad367f85be"
  },
  "history": []
}

```