Back to skill

Security audit

Neckr0ik Security Scanner

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local security scanner, but it can print unredacted secrets found in scanned files and has documented security-coverage claims that the implementation does not fully meet.

Install only if you are comfortable with a local scanner reading the skill directories you point it at. Treat JSON and Markdown reports as sensitive, because they may contain copied secret lines from scanned code, and do not rely on it as a complete OpenClaw skill approval gate without manual review of SKILL.md and other Markdown instructions.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/audit.py:221
Finding
Detected Secrets Are Reproduced in JSON and Markdown Reports## Vulnerability Details **File Location**: `scripts/audit.py:221-230`, `scripts/audit.py:64-78`, `scripts/audit.py:589-603`, `scripts/audit.py:650` **Vulnerability Type**: Sensitive information exposure through audit output **Risk Level**: Medium ### Vulnerable Code ```python vulnerabilities.append(Vulnerability( id=f"SECRET-{name.upper().replace(' ', '-')}", name=f"Hardcoded {name}", severity=Severity.CRITICAL, file=str(filepath), line=line_num, description=f"Potential hardcoded {name.lower()} detected in code. This exposes credentials and should be moved to environment variables.", code_snippet=line.strip()[:200], remediation=f"Move the {name.lower()} to an environment variable and access it via os.environ.get() or use a secrets manager.", references=["https://owasp.org/www-community/vulnerabilities/Hardcoded_password"] )) ``` The captured line is subsequently included in serialized results: ```python def to_dict(self) -> dict: return { "skill_name": self.skill_name, "skill_path": self.skill_path, "passed": self.passed, "vulnerabilities": [ { "id": v.id, "name": v.name, "severity": v.severity.value, "file": v.file, "line": v.line, "description": v.description, "code_snippet": v.code_snippet, "remediation": v.remediation, "references": v.references } for v in self.vulnerabilities ], "summary": self.summary } ``` Markdown output also reproduces it: ```python lines.extend([ f"### {v.name}", "", f"- **ID:** {v.id}", f"- **Severity:** {v.severity.value.upper()}", f"- **File:** `{v.file}:{v.line}`", f"- **Description:** {v.description}", f"- **Code:** `{v.code_snip ...[truncated 2392 chars]
Remediation
## Remediation Suggestions 1. Never store the complete matching line for secret findings. 2. Redact the matched span immediately during detection rather than relying only on output-time filtering. 3. Replace captured values with a fixed marker such as `[REDACTED]`, optionally retaining only a short non-sensitive suffix for identification. 4. Apply centralized defense-in-depth redaction before producing JSON, Markdown, or summary output. 5. Avoid including private-key bodies, connection-string passwords, authorization headers, or environment-variable values in any report field. 6. Add regression tests containing synthetic secrets and assert that none of those values appear in serialized reports or stdout. 7. Document that existing reports and CI logs generated by affected versions should be treated as potentially sensitive. 8. Rotate any real credentials that have already appeared in retained reports. Example masking approach: ```python matched_line = lines[line_num - 1] if line_num <= len(lines) else "" start = match.start() - content.rfind("\n", 0, match.start()) - 1 end = start + len(match.group(0)) redacted_line = matched_line[:start] + "[REDACTED]" + matched_line[end:] vulnerabilities.append(Vulnerability( # Other fields omitted code_snippet=redacted_line[:200], )) ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/audit.py:185
Finding
Markdown Exclusion Creates a Prompt-Injection and Unsafe-Instruction Detection Gap## Vulnerability Details **File Location**: `scripts/audit.py:185-190`, `scripts/audit.py:397-475` **Vulnerability Type**: Security scanner false negative caused by excluded Agent instruction files **Risk Level**: Medium ### Vulnerable Code ```python def scan_file(filepath: Path) -> List[Vulnerability]: """Scan a single file for vulnerabilities.""" vulnerabilities = [] # Skip documentation and example files if filepath.suffix == '.md': return vulnerabilities if 'example' in filepath.name.lower(): return vulnerabilities if 'doc' in filepath.name.lower() and filepath.suffix in ['.txt', '.rst']: return vulnerabilities ``` The separate manifest check only searches `SKILL.md` for secrets and basic frontmatter properties: ```python def check_skill_manifest(skill_path: Path) -> List[Vulnerability]: """Check SKILL.md for security issues.""" vulnerabilities = [] skill_md = skill_path / "SKILL.md" if not skill_md.exists(): vulnerabilities.append(Vulnerability( id="MANIFEST-MISSING", name="Missing SKILL.md", severity=Severity.CRITICAL, file="SKILL.md", line=0, description="Skill is missing required SKILL.md manifest file.", code_snippet="", remediation="Create a SKILL.md file with proper YAML frontmatter.", references=[] )) return vulnerabilities try: content = skill_md.read_text() # Check for secrets in manifest for pattern, name in SECRET_PATTERNS: if re.search(pattern, content, re.IGNORECASE): vulnerabilities.append(Vulnerability( id=f"MANIFEST-SECRET-{name.upper().replace(' ', '-')}", name=f"Secret in SKILL.md", severity=Severi ...[truncated 2867 chars]
Remediation
## Remediation Suggestions 1. Do not categorically exclude `SKILL.md` or other Agent-facing instruction files. 2. Introduce a dedicated instruction-content scanner rather than applying only source-code regexes to Markdown. 3. Detect patterns associated with session-goal replacement, safety-rule suppression, role hijacking, forced report content, sensitive-data collection, persistence requests, and remote download-and-execute instructions. 4. Parse YAML frontmatter separately from the Markdown body so metadata and instructions can be evaluated with appropriate rules. 5. Scan all files that may be loaded into Agent context, including referenced Markdown documents. 6. Report instruction findings with exact file and line locations. 7. Treat obfuscated or dynamically assembled external instructions as requiring manual review. 8. Add adversarial tests in which malicious instructions appear exclusively in `SKILL.md` and verify that the audit fails or emits a high-confidence warning. 9. Clearly communicate that regex scanning cannot prove a Skill safe and should complement, not replace, semantic review and runtime sandboxing.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Credential Access

High
Category
Privilege Escalation
Content
import os
from dotenv import load_dotenv

load_dotenv()  # Load from .env file

api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
import os
from dotenv import load_dotenv

load_dotenv()  # Load from .env file

api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Use shlex.quote() to escape user input
safe_input = shlex.quote(user_input)
subprocess.run(f"echo {safe_input}", shell=True)
```

---
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Examples:**
```python
# VULNERABLE
subprocess.run(f"ls {user_input}", shell=True)
```

**Risk:** Command injection via shell metacharacters.
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

YARA rule 'offensive_tool_references': References to well-known offensive security tools [hacktools]

High
Category
YARA Match
Content
s?://([^"\']+)["\']', "aiohttp request to external domain"),
    (r'\.fetch\s*\(["\']https?://([^"\']+)["\']', "fetch request to external domain"),
    (r'axios\.(?:get|post|put|delete)\s*\(["\']https?://([^"\']+)["\']', "axios request to external domain"),
]

# Known suspicious domains
SUSPICIOUS_DOMAINS = [
    r'pastebin\.com',
    r'webhook\.site',
    r'requestbin\.',
    r'ngrok\.io',
    r'burpcollaborator',
    r'interactsh',
]

# Known safe domains (whitelisted)
SAFE_DOMAINS = [
    r'api\.openai\.com',
    r'api\.anthropic\.com',
    r'github\.com',
    r'api\.github\.com',
    r'pypi\.org',
    r'npmjs\.com',
    r'clawhub\.ai',
    r'openclaw\.ai',
    r'localhost',
    r'127\.0\.0\.1',
]

# Prompt injection patterns
PROMPT_INJECTION_PATTERNS = [
    (r'f["\'][^"\']*\{[^}]*user[^}]*\}[^"\']*["\']', "f-string with user input in prompt"),
    (r'\.format\s*\([^)]*user', ".format() with user input"),
    (r'%\s*\(.*user', "% formatting with user input"),
    (r'system\s*[=:]\s
Confidence
70% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

YARA rule 'offensive_tool_references': References to well-known offensive security tools [hacktools]

High
Category
YARA Match
Content
s?://([^"\']+)["\']', "aiohttp request to external domain"),
    (r'\.fetch\s*\(["\']https?://([^"\']+)["\']', "fetch request to external domain"),
    (r'axios\.(?:get|post|put|delete)\s*\(["\']https?://([^"\']+)["\']', "axios request to external domain"),
]

# Known suspicious domains
SUSPICIOUS_DOMAINS = [
    r'pastebin\.com',
    r'webhook\.site',
    r'requestbin\.',
    r'ngrok\.io',
    r'burpcollaborator',
    r'interactsh',
]

# Known safe domains (whitelisted)
SAFE_DOMAINS = [
    r'api\.openai\.com',
    r'api\.anthropic\.com',
    r'github\.com',
    r'api\.github\.com',
    r'pypi\.org',
    r'npmjs\.com',
    r'clawhub\.ai',
    r'openclaw\.ai',
    r'localhost',
    r'127\.0\.0\.1',
]

# Prompt injection patterns
PROMPT_INJECTION_PATTERNS = [
    (r'f["\'][^"\']*\{[^}]*user[^}]*\}[^"\']*["\']', "f-string with user input in prompt"),
    (r'\.format\s*\([^)]*user', ".format() with user input"),
    (r'%\s*\(.*user', "% formatting with user input"),
    (r'system\s*[=:]\s
Confidence
70% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill documentation describes capabilities involving environment access, file reads, network operations, and shell-based auditing commands, but the manifest does not declare any explicit tool scope such as permissions or allowed-tools. That mismatch is risky because reviewers and enforcement systems cannot clearly constrain what the skill is expected to access, increasing the chance of overbroad execution or abuse if the implementation invokes sensitive tools.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
This markdown file includes a natural-language allowlist under 'Whitelisted Domains' stating that certain domains are considered safe for network requests. Such blanket policy language imposes an organizational constraint in prose without explaining scope, exceptions, or user opt-in, which fits the policy-violation category more than a technical scanner finding.