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

Content
View full 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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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
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.

Content

Scanner excerpt · SKILL.md (reported line 22)May include surrounding context.

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

Instruction Override

High
Category
Prompt Injection
Confidence
80% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 42)May include surrounding context.

md
## 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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/rule_engine.py (reported line 99)May include surrounding context.

python
# Common hidden files that are NOT suspicious
    SAFE_HIDDEN_FILES = {
        ".gitignore", ".gitkeep", ".gitattributes", ".editorconfig",
        ".npmrc", ".nvmrc", ".python-version", ".tool-versions",
        ".eslintrc", ".prettierrc", ".dockerignore",
    }

Credential Access

High
Category
Privilege Escalation
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.

Content

Scanner excerpt · scripts/rule_engine.py (reported line 169)May include surrounding context.

python
".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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/rules/data_exfiltration.yaml (reported line 28)May include surrounding context.

yaml
description_zh: "SSH 密钥访问"

    - id: DE005
      pattern: "keychain|login\\.keychain|security find"
      description: "macOS Keychain access"
      description_zh: "macOS 钥匙串访问"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/rules/data_exfiltration.yaml (reported line 29)May include surrounding context.

yaml
- id: DE005
      pattern: "keychain|login\\.keychain|security find"
      description: "macOS Keychain access"
      description_zh: "macOS 钥匙串访问"

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
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scripts/rules/obfuscation.yaml (reported line 2)May include surrounding context.

yaml
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 隐藏�

Instruction Override

High
Category
Prompt Injection
Confidence
90% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · scripts/rules/prompt_injection.yaml (reported line 8)May include surrounding context.

yaml
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

Self-Modification

High
Category
Rogue Agent
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.

Content

Scanner excerpt · scripts/rules/prompt_injection.yaml (reported line 23)May include surrounding context.

yaml
- 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

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
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scripts/rules/prompt_injection.yaml (reported line 23)May include surrounding context.

yaml
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

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · scripts/rules/prompt_injection.yaml (reported line 18)May include surrounding context.

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

    - id: PI004

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
SKILL.md:42