Back to skill

Security audit

Skill Auditor (于松涛版)

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent security scanner, but its file-reading logic can escape the intended audit folder through symlinks and may give falsely clean reports.

Install only if you are comfortable giving it read access to directories you explicitly choose. Avoid scanning untrusted skill archives that may contain symlinks unless they are unpacked in a sandbox, and treat clean reports as heuristic pattern-scan results rather than proof that a skill is safe.

Vulnerability Patterns
  • 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
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
auditor.py:94
Finding

Audit Root Escape Through Symbolic-Link File Reads

Content
View full analysis

Vulnerability Details

File Location: auditor.py, lines 94-101 and 127-134
Vulnerability Type: Symbolic-link path traversal and unauthorized file read
Risk Level: Medium

Vulnerable Code

python
try:
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()
except UnicodeDecodeError:
    # If it's not a text file, skip it
    return issues
except Exception:
    # If we can't read the file for any reason, skip it
    return issues
python
# Check all Python and shell files in the skill directory
for file_path in skill_path.rglob("*"):
    if file_path.is_file() and (file_path.suffix in ['.py', '.sh', '.js', '.ts', '.json', '.yaml', '.yml'] or 
                               file_path.name in ['SKILL.md', 'skill.json']):
        issues = self.scan_file(str(file_path))
        all_issues.extend(issues)

Technical Analysis

The scanner recursively discovers files under a user-supplied Skill directory and opens each selected path without rejecting symbolic links. It also does not resolve the candidate path and verify that its target remains under the resolved audit root.

On common filesystems, Path.is_file() follows symbolic links. Consequently, a symbolic link located inside the audited directory can point to a regular file outside that directory and still pass the file check. scan_file() then follows the link when calling open().

The external file is read using the auditor process's privileges. If its contents match a configured expression, the matching data is stored in matched_text and may be exposed through generate_report(). The weakness is constrained by the process's filesystem permissions and the scanner's filename or extension filters, but a link can be assigned an accepted name such as leak.py.

Attack Path

  1. An attacker prepares a Skill directory that will be submitted for auditing.
  2. The attacker creates a symbolic ...[truncated 1126 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve the audit root once with Path(skill_path).resolve(strict=True).
  2. Reject every discovered path for which file_path.is_symlink() is true.
  3. Resolve each candidate and verify that it remains under the resolved root using candidate.relative_to(root) inside exception handling.
  4. Open files in a way that prevents link following where the platform supports it, such as os.open() with O_NOFOLLOW.
  5. Revalidate the opened file descriptor to reduce time-of-check/time-of-use race conditions.
  6. Run the auditor under a sandboxed, unprivileged account with access limited to the submitted directory.
  7. Avoid including raw matched content in reports. Prefer rule identifiers, line numbers, and redacted excerpts.
  8. Record rejected links as explicit scan errors rather than silently ignoring them.

T09 · Insecure Skill Coding Practices

Warning
Location
auditor.py:96
Finding

Fail-Open Scanning and Restricted File Selection Permit Payload Evasion

Content
View full analysis

Vulnerability Details

File Location: auditor.py, lines 96-101, 127-130, and 244-246
Vulnerability Type: Incomplete security scanning with misleading clean results
Risk Level: Medium

Vulnerable Code

python
except UnicodeDecodeError:
    # If it's not a text file, skip it
    return issues
except Exception:
    # If we can't read the file for any reason, skip it
    return issues
python
# Check all Python and shell files in the skill directory
for file_path in skill_path.rglob("*"):
    if file_path.is_file() and (file_path.suffix in ['.py', '.sh', '.js', '.ts', '.json', '.yaml', '.yml'] or 
                               file_path.name in ['SKILL.md', 'skill.json']):
        issues = self.scan_file(str(file_path))
        all_issues.extend(issues)
python
if not scan_result['all_issues']:
    report_lines.append("NO SECURITY ISSUES FOUND")
    report_lines.append("This skill appears to be secure based on the current audit rules.")

Technical Analysis

The scanner treats decoding failures and all other file-read exceptions as if the affected file contained no findings. It does not preserve an error or incomplete-scan status. File selection is also based on a small, case-sensitive suffix allowlist plus two exact filenames.

As a result, executable or security-relevant content can avoid inspection when it is:

  • Stored in an extensionless executable file.
  • Assigned an unsupported suffix.
  • Assigned an uppercase suffix such as .PY.
  • Encoded in a format that is not valid UTF-8.
  • Made unreadable to the scanner while remaining usable by another component or runtime.

Because skipped files and errors are not represented in all_issues, generate_report() can state NO SECURITY ISSUES FOUND even though part of the package was never analyzed. The vulnerability is therefore not simply reduced scanner coverage; it is a fail-open result that can create ...[truncated 1426 chars]

Remediation
View remediation

Remediation Suggestions

  1. Track every skipped, unreadable, or undecodable file in a dedicated scan_errors or unscanned_files collection.
  2. Mark the overall result as incomplete whenever any candidate file cannot be analyzed.
  3. Never emit an unqualified clean verdict for an incomplete scan. Distinguish among “no findings,” “incomplete,” and “failed.”
  4. Normalize suffixes with file_path.suffix.lower() before comparison.
  5. Inspect extensionless files, executable files, manifest-referenced entry points, and files identified as scripts by content or shebang.
  6. Consider scanning every regular file subject to explicit size and resource limits rather than relying solely on filename extensions.
  7. Detect file types using content signatures where practical and handle supported encodings deliberately.
  8. Treat read failures as audit findings or blocking errors in security-sensitive workflows.
  9. Add adversarial tests covering uppercase extensions, extensionless scripts, invalid UTF-8, unreadable files, and packages containing mixed scanned and unscanned content.
  10. Reword the clean result to clarify that it means no configured pattern was detected in successfully scanned files, not that the Skill is conclusively secure.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The entire skill description and usage guidance are written in Chinese, and the file does not indicate that language selection is optional or that the skill is intended only for a Chinese-speaking or region-specific audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

This JSON manifest/config defines security patterns and reporting sections but provides no explicit skill invocation phrases, activation constraints, or exclusion conditions. For manifest files, the absence of any trigger specificity can make it unclear when the skill should activate versus when it should not.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation is entirely written in Chinese, including the title, feature description, and usage guidance, with no indication that users may choose another language or that the skill is region-specific. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest's natural-language description is written only in Chinese, with no indication that the skill supports user language choice or that it is intentionally limited to a Chinese-speaking context. Under the policy rule, a language-specific constraint should either be optional for the user or clearly documented and justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.