Back to skill

Security audit

Senseguard

Security checks for vulnerabilities and agentic risk

Overview

This is a local skill security scanner, but it needs review because its advertised semantic checks are fail-open and its file scanning/cache behavior can read or retain more local data than expected.

Install only if you are comfortable with a local scanner reading the skill directories you point it at and writing scan results to its cache. Avoid scanning untrusted directories that may contain symlinks or secret-bearing files, treat Layer 2 results as incomplete unless run in an isolated tool-less review context, and do not rely on a SAFE rating as proof that semantic analysis actually occurred.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scanner.py:112
Finding
Semantic analysis fails open and reports a safe default without performing analysis## Vulnerability Details **File Location**: `scripts/scanner.py:112-131`, `scripts/semantic_analyzer.py:132-163` **Vulnerability Type**: Fail-open security analysis and misleading risk classification **Risk Level**: High ### Vulnerable Code ```python # Determine if Layer 2 should run run_layer2 = deep or layer1_result.has_suspicious layers_used = ["Layer 1 (Rules)"] layer2_result = None layer2_prompt = None if run_layer2: layers_used.append("Layer 2 (Semantic)") frontmatter = get_frontmatter(skill_dir) or {} full_content = get_skill_content(skill_dir) layer2_prompt = semantic_analyzer.build_analysis_prompt( name=frontmatter.get("name", skill_name), description=frontmatter.get("description", ""), full_content=full_content, ) # NOTE: In actual OpenClaw usage, the agent would process this prompt # and feed back the JSON result. For CLI standalone testing, we use # the default result. layer2_result = semantic_analyzer.get_default_result() else: layer2_result = semantic_analyzer.get_default_result() ``` The default result is explicitly classified as safe: ```python def get_default_result(self) -> dict: """Return a default (safe) result when LLM analysis is not performed.""" return { "prompt_injection": { "detected": False, "confidence": 0.0, "evidence": [], "technique": "none", "explanation": "Layer 2 analysis not performed", }, "permission_analysis": { "declared_purpose": "unknown", "actual_capabilities": [], "overprivileged": False, "explanation": "Layer 2 analysis not performed", }, "data_access": { "sensitive_data_accessed": [], "data_sent_externally": False, "external_endpoints": [], }, "hidd ...[truncated 2297 chars]
Remediation
## Remediation Suggestions - Represent missing semantic analysis as `unknown`, `incomplete`, or `analysis_unavailable`, never `safe`. - Do not add `"Layer 2 (Semantic)"` to `layers_used` unless an actual semantic response has been received and validated. - Implement a defined response-input mechanism, API callback, or direct model integration that feeds the analysis result into `parse_llm_response()` and the scorer. - Validate semantic responses against a strict schema, including field types, allowed risk values, and confidence ranges. - Fail closed for `--deep`: return a nonzero status or an incomplete-assessment warning if semantic analysis cannot be performed. - Prevent metadata bonuses from masking an unavailable security layer. - Clearly distinguish “not detected” from “not analyzed” in JSON and Markdown reports.

T01 · Skill Instruction Hijacking

Error
Location
scripts/semantic_analyzer.py:69
Finding
Untrusted Skill instructions are embedded directly into a host-agent analysis prompt## Vulnerability Details **File Location**: `scripts/semantic_analyzer.py:12-61`, `scripts/semantic_analyzer.py:69-75` **Vulnerability Type**: Indirect prompt injection through untrusted scanned content **Risk Level**: High ### Vulnerable Code ```python ANALYSIS_PROMPT_TEMPLATE = """You are an AI Agent security auditing expert. Analyze the following OpenClaw skill content for security risks. Skill name: {name} Skill description: {description} Skill full content: --- {full_content} --- Analyze for the following threats and output ONLY valid JSON (no markdown, no explanation outside JSON): {{ "prompt_injection": {{ "detected": true/false, "confidence": 0.0-1.0, "evidence": ["exact suspicious text snippets from the skill"], "technique": "role hijacking / instruction override / hidden instructions / ...", "explanation": "why this content may be an injection attack" }}, "permission_analysis": {{ "declared_purpose": "what the skill claims to do", "actual_capabilities": ["list of actual capabilities needed"], "overprivileged": true/false, "explanation": "whether permissions exceed declared functionality" }}, "data_access": {{ "sensitive_data_accessed": ["list of sensitive data types accessed"], "data_sent_externally": true/false, "external_endpoints": ["discovered external URLs/IPs"] }}, "hidden_instructions": {{ "detected": true/false, "instructions": ["discovered hidden instructions"], "technique": "what hiding technique was used" }}, "behavioral_risk": {{ "modifies_agent_config": true/false, "creates_persistence": true/false, "bypasses_confirmation": true/false, "explanation": "behavioral risk analysis" }}, "overall_risk": "safe|caution|dangerous|malicious", "summary": "one-sentence summary" }} Important: - Be thorough but avoid false positives. Common patterns like r ...[truncated 2639 chars]
Remediation
## Remediation Suggestions - Process semantic-analysis requests in a dedicated, tool-less, least-privileged model context. - Place scanned content in a structured data field rather than concatenating it directly with operational instructions. - Add explicit higher-priority instructions stating that all Skill content is untrusted evidence and that commands found inside it must never be followed. - Encode or length-prefix the content so attacker-supplied delimiters cannot imitate the surrounding prompt structure. - Treat the name and description as untrusted data in the same way as the full content. - Require strict schema validation for the response and reject unexpected fields, malformed types, or content outside the JSON object. - Use deterministic output constraints where supported and independently combine semantic results with static evidence. - Never expose shell, filesystem-write, network, memory-write, or credential tools to the semantic-analysis context.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/rule_engine.py:187
Finding
Target scanning follows symbolic-link files outside the requested Skill directory## Vulnerability Details **File Location**: `scripts/rule_engine.py:187-224`, `scripts/cache_manager.py:49-68` **Vulnerability Type**: Out-of-scope local file read through symbolic links **Risk Level**: Medium ### Vulnerable Code ```python files = [] for root, dirs, filenames in os.walk(skill_dir): # Skip hidden directories and cache dirs[:] = [d for d in dirs if not d.startswith(".") and d not in skip_dirs] for fname in filenames: fpath = os.path.join(root, fname) ext = os.path.splitext(fname)[1].lower() # Include files with known text extensions or no extension if ext in text_extensions or ext == "": files.append(fpath) # Also include SKILL.md explicitly (no ext check needed, but safety) elif fname == "SKILL.md": files.append(fpath) return list(set(files)) # deduplicate ``` ```python def _scan_file(self, file_path: str, result: Layer1Result): """Scan a single file against all loaded rules.""" try: with open(file_path, "r", encoding="utf-8", errors="replace") as f: lines = f.readlines() except (OSError, IOError): return # Also check for zero-width characters at the raw byte level try: with open(file_path, "rb") as f: raw_bytes = f.read() self._check_zero_width(raw_bytes, file_path, result) except (OSError, IOError): pass ``` The cache hash operation has the same issue: ```python def compute_hash(self, skill_dir: str) -> str: """Compute SHA-256 hash of all files in a skill directory.""" hasher = hashlib.sha256() file_entries = [] for root, dirs, filenames in os.walk(skill_dir): # Skip hidden dirs, cache, __pycache__ dirs[:] = sorted(d for d in dirs if not d.startswith(".") and d not in ("__pycache__", "cache")) for fname in sorted(filenames): ...[truncated 2285 chars]
Remediation
## Remediation Suggestions - Reject symbolic-link files and directories with `os.path.islink()` or `os.lstat()` before opening them. - Resolve the Skill root and each candidate path using `os.path.realpath()`. - Verify containment using `os.path.commonpath()` and reject any resolved path outside the resolved Skill root. - Open files using no-follow semantics where the platform supports them, such as `O_NOFOLLOW`, to reduce time-of-check-to-time-of-use races. - Apply the same containment policy consistently in rule scanning, hashing, structure checks, and content helpers. - Enforce per-file and total-scan byte limits before reading content. - Avoid reading whole files into memory when hashing; process them in bounded chunks. - Redact potentially sensitive evidence before writing reports or cache entries.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A second, more specific mismatch indicates the skill does not itself detect prompt injection, exfiltration, or hidden instructions, despite explicitly claiming to do so. In a security tool, overstated detection capability is itself a significant security risk because operators may rely on inaccurate results and fail to identify malicious skills.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
A second, more specific mismatch indicates the skill does not itself detect prompt injection, exfiltration, or hidden instructions, despite explicitly claiming to do so. In a security tool, overstated detection capability is itself a significant security risk because operators may rely on inaccurate results and fail to identify malicious skills.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
annot detect.

Traditional scanners see SKILL.md as a text file. SenseGuard sees it as **agent instructions** and checks for prompt injection, data exfiltration, obfuscation, and persistence attacks.

## How to Use

When the user asks to scan a skill:

```bash
python3 scripts/scanner.py --target <skill-name-or-path>
```

Options:
- `--target all` — scan all installed skills
- `--deep` — force LLM semantic analysis (Layer 2)
- `--no-cache` — skip cached results
- `--json` — output raw JSON for further processing

### Layer 2 (Semantic Analysis)

When `--json` output contains a `layer2_prompt` field, process it as a security audit task, then feed the JSON result back to generate the final score. This is how the LLM analyzes intent beyond regex patterns.

## Output

The scanner outputs a Markdown risk report with:
- Score (0-100) and rating: SAFE / CAUTION / DANGEROUS / MALICIOUS
- Findings with rule IDs, evidence text, and line numbers
- Actionable recommendations

For CRITICAL f
Confidence
80% confidence
Finding
The skill instructs the operator to process a `layer2_prompt` field from JSON and feed the result back into scoring. Because that prompt originates from scanned content or an intermediate pipeline, this creates a prompt-injection surface where untrusted text can influence the analyst or downstream LLM, especially in a tool specifically handling adversarial skill content.

Instruction Override

High
Category
Prompt Injection
Content
## Key Differentiator

SenseGuard catches what VirusTotal cannot:
- `"ignore all previous instructions"` — prompt injection
- `curl -X POST` hidden in Markdown — data exfiltration
- Zero-width characters hiding commands — obfuscation
- `"modify MEMORY.md"` — persistence attacks
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Credential Access

High
Category
Privilege Escalation
Content
# Common hidden files that are NOT suspicious
    SAFE_HIDDEN_FILES = {
        ".gitignore", ".gitkeep", ".gitattributes", ".editorconfig",
        ".npmrc", ".nvmrc", ".python-version", ".tool-versions",
        ".eslintrc", ".prettierrc", ".dockerignore",
    }
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
".md", ".txt", ".yaml", ".yml", ".json", ".py", ".sh",
            ".bash", ".zsh", ".js", ".ts", ".rb", ".pl", ".lua",
            ".toml", ".ini", ".cfg", ".conf", ".xml", ".html",
            ".css", ".env", ".dockerfile",
        }
        
        # Directories to always skip
Confidence
84% confidence
Finding
Including .env in the set of scannable text files means the engine will read files that commonly store secrets such as API keys, tokens, and database credentials. In the context of a security scanner skill, this increases sensitivity because scan results may capture matched secret material as evidence and propagate it into logs, reports, or downstream analysis, creating accidental secret exposure.

Credential Access

High
Category
Privilege Escalation
Content
description_zh: "SSH 密钥访问"

    - id: DE005
      pattern: "keychain|login\\.keychain|security find"
      description: "macOS Keychain access"
      description_zh: "macOS 钥匙串访问"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- id: DE005
      pattern: "keychain|login\\.keychain|security find"
      description: "macOS Keychain access"
      description_zh: "macOS 钥匙串访问"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
category: obfuscation
description: "Obfuscation technique detection rules"

rules:
  high:
    - id: OB001
      pattern: "\\u200b|\\u200c|\\u200d|\\ufeff"
      description: "Zero-width character hidden text"
      description_zh: "零宽字符隐藏文本"

    - id: OB002
      pattern: "<!--.*(?:instruction|prompt|ignore|override|execute|command|system).*-->"
      description: "Instructions hidden in HTML comments"
      description_zh: "HTML 注释中隐藏指令"

    - id: OB003
      pattern: "\\[//\\]:\\s*#|\\[hidden\\]"
      description: "Markdown hidden content"
      description_zh: "Markdown 隐藏�
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Instruction Override

High
Category
Prompt Injection
Content
critical:
    - id: PI001
      pattern: "ignore (all |any )?(previous|prior|above|earlier) \\w*\\s*(instructions|prompts|rules|guidelines)"
      description: "Override system instructions"
      description_zh: "试图覆盖系统指令"

    - id: PI002
Confidence
90% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Self-Modification

High
Category
Rogue Agent
Content
- id: PI004
      pattern: "(ignore|disable|bypass|delete|remove).{0,30}(safety|security|filter|restriction|guard|protection|check)"
      description: "Disable safety mechanisms"
      description_zh: "禁用安全机制"

    - id: PI005
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
king"
      description_zh: "角色劫持"

    - id: PI003
      pattern: "do not (ask|request|require|need) (for )?(permission|confirmation|approval)"
      description: "Bypass user confirmation"
      description_zh: "绕过用户确认"

    - id: PI004
      pattern: "(ignore|disable|bypass|delete|remove).{0,30}(safety|security|filter|restriction|guard|protection|check)"
      description: "Disable safety mechanisms"
      description_zh: "禁用安全机制"

    - id: PI005
      pattern: "system prompt|<<SYS>>|<s>\\[INST\\]"
      description: "System prompt injection markers"
      description_zh: "系统提示词注入标记"

  high:
    - id: PI006
      pattern: "pretend (to be|you are)|act as if|roleplay as"
      description: "Roleplay attack"
      description_zh: "角色扮演攻击"

    - id: PI007
      pattern: "do not (tell|inform|notify|alert) the user"
      description: "Hide actions from user"
      description_zh: "对用户隐瞒行为"

    - id: PI008
Confidence
80% 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
84% confidence
Finding
The skill advertises executable behavior via `python3 scripts/scanner.py` and the static findings indicate file read/write capability, yet the manifest declares no explicit tool scope or permissions. For a security-sensitive skill, undeclared filesystem access weakens reviewability and can enable broader-than-expected data access or local state modification, especially if scanning arbitrary skill paths or maintaining caches.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This code requires every Finding to carry a `description_zh` field, and later populates it directly from rule metadata. That implies a hard-coded language expectation in the skill’s natural-language outputs without any visible opt-in, fallback, or justification for a Chinese-only locale requirement.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- id: PI003
      pattern: "do not (ask|request|require|need) (for )?(permission|confirmation|approval)"
      description: "Bypass user confirmation"
      description_zh: "绕过用户确认"

    - id: PI004
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The module docstring states that the CLI orchestrates Layer 2 semantic scanning, but the implementation does not do so and instead returns a default result. This documentation/behavior mismatch is dangerous in a security tool because operators may rely on nonexistent protections and miss malicious skill content that only semantic analysis would detect.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The code advertises semantic scanning but, in the CLI path, only builds a Layer 2 prompt and then substitutes a default result rather than performing any real semantic analysis. This can create a false sense of security, causing users to trust scans that never evaluated prompt-injection or hidden-instruction content, which is especially risky in a security scanner.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The fallback path returns a structured result with "overall_risk": "safe" even though the analyzer explicitly states that Layer 2 analysis was not performed. In a security-scanning skill, this fail-open behavior can cause upstream components or users to treat unanalyzed or parser-broken content as trustworthy, suppressing further review and creating a bypass for malicious skills that break or avoid LLM analysis.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The code emits bilingual output via a hard-coded Chinese description string for prompt-injection findings. Because this file provides no user opt-in, locale selection, or justification for always including Chinese text, it may violate the language/locale policy requirement.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Several human-facing report strings are emitted in Chinese (for example at L260, L273, L285, L297, L307, and L317) in addition to English. The file does not indicate that the user can choose language or that this locale behavior is required for a region-specific purpose.

Intent-Code Divergence

Low
Confidence
84% confidence
Finding
The module docstring makes a concrete operational claim about execution cost and speed. While 'zero LLM cost' is consistent, 'millisecond execution' is not guaranteed by code that scans entire directory trees, opens files, and applies regexes over their contents, especially on larger skills.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The YAML includes paired English and Chinese descriptions via `description_zh`, which hard-codes a specific locale into the skill metadata. There is no indication that Chinese output is optional, user-selected, or required for a region-specific purpose, so this may violate language/locale policy expectations.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This manifest-like YAML file includes a Chinese description field alongside English text, but there is no visible indication in this file that language selection is optional, user-configurable, or scoped to a region-specific use case. Under the language/locale policy check, hard-coded locale content can be a policy concern when no user opt-in or justification is present.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The file continues to define Chinese-language description text directly in configuration, but provides no surrounding natural-language statement that users can choose their preferred language. Without documented opt-in or region-specific justification, this may violate language/locale policy expectations.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This line contains Chinese localized content in a general YAML rules file, while no explicit user language selection mechanism or locale constraint is described here. That creates a potential language/locale policy issue under the natural-language policy rules.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
SKILL.md:42