Back to skill

Security audit

Skill Sentinel

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate skill-auditing helper, but its auto-fix mode can rewrite skill files and lacks safeguards against unintended out-of-scope writes.

Review this before installing if you manage important local skills. Use audit mode without --fix first, pass a specific trusted --skills-dir, avoid running it with elevated privileges, and inspect proposed changes before allowing automatic remediation.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/audit_skills.py:255
Finding

Uncontained File Write Through Symbolic-Link Traversal

Content
View full analysis

Vulnerability Details

File Location: scripts/audit_skills.py:255-268
Vulnerability Type: Symbolic-link traversal and out-of-scope file overwrite
Risk Level: Medium

Vulnerable Code

python
try:
    content = sf.read_text(encoding='utf-8')
except Exception as e:
    report['skills'].append({
        'path': str(sf),
        'error': f'Cannot read file: {e}',
        'score': 0,
    })
    report['issues_found'] += 1
    continue

fm, body = parse_frontmatter(content)

if fm is None:
    report['skills'].append({
        'path': str(sf),
        'error': 'No YAML frontmatter found',
        'score': 0,
        'issues': ['CRITICAL: Missing YAML frontmatter (--- ... ---)'],
        'suggestions': ['Add frontmatter with name: and description: fields'],
    })
    report['issues_found'] += 1
    continue

skill_info = {
    'path': str(sf),
    'name': fm['name'] or 'MISSING',
    'description_length': len(fm['description'] or ''),
}

if fm['colon_issue']:
    skill_info['issues'] = ['YAML: Colon in description may break parsing']
    skill_info['auto_fix'] = 'Wrap description in quotes'
    report['issues_found'] += 1

    if auto_fix:
        fixed = auto_fix_colon(content)
        if fixed:
            sf.write_text(fixed)
            skill_info['fixed'] = True

The generated replacement is created by the following code at scripts/audit_skills.py:310-322:

python
def auto_fix_colon(content: str) -> Optional[str]:
    """Fix unquoted colons in YAML description field."""
    lines = content.split('\n')
    fixed = False
    for i, line in enumerate(lines):
        if line.strip().startswith('description:'):
            val = line.split('description:', 1)[1].strip()
            if ':' in val and not val.startswith('"') and not val.startswith("'"):
                lines[i] = f'description: "{val}"'
                fixed = True
            break
    return '\n'.join(lines) if fixed else None

Technical Analysis

The recursive d ...[truncated 2424 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic-link candidates before reading or writing:

    python
    if sf.is_symlink():
        # Report and skip the unsafe entry.
        continue
    
  2. Resolve both the scan root and each candidate, then enforce containment:

    python
    root = Path(skills_dir).resolve()
    candidate = sf.resolve(strict=True)
    if not candidate.is_relative_to(root):
        # Report and skip the out-of-scope target.
        continue
    
  3. Revalidate containment and file identity immediately before writing to reduce time-of-check/time-of-use exposure.

  4. Where supported, open the destination with no-follow semantics such as O_NOFOLLOW, and verify with fstat() that it is a regular file.

  5. Write to a safely created temporary file in the same verified directory, flush and synchronize it, then atomically replace the original after repeating the safety checks.

  6. Replace the regular-expression-based YAML transformation with a safe YAML parser and serializer. Ensure embedded quotes, line breaks, backslashes, and other YAML-special characters are escaped correctly.

  7. Avoid running the audit or automatic-fix mode with elevated privileges. Consider making audit mode read-only by default and requiring explicit confirmation for each modified file.

Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill instructs users to run local scripts and apply auto-remediation, which implies file read/write behavior, but the frontmatter does not declare any tool scope or permissions boundaries. In agents that enforce or surface tool permissions, this creates an unnecessary trust gap and can lead to broader-than-expected file access during troubleshooting or automated fixes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation text is very broad and overlaps with generic troubleshooting requests such as skills not firing, audits, optimization, and proactive checks. Over-broad trigger criteria can cause the skill to activate in many unrelated contexts, increasing prompt injection exposure, consuming context budget, and potentially steering the agent into performing file inspection or modification when a narrower skill would be safer.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
**Bad:** `"Helps with documents."` — no trigger, just capability
**Good:** `"Use when the user asks to extract form fields, fill, redact, or parse tables from a PDF file."`

**Fix:** Rewrite using the Description Design Pattern below.

### 2. YAML Frontmatter Format Error

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The top-level docstring states the script 'Scans skill directories for triggering issues and outputs a diagnostic report.' In contrast, the implementation conditionally calls auto_fix_colon and then writes the modified content back to disk with sf.write_text(fixed), creating side effects not reflected in the documentation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description includes diagnosis, prevention, and auto-remediation, so some fixing behavior is in scope overall. However, this file's own module docstring says it 'scans skill directories for triggering issues and outputs a diagnostic report,' while the implemented --fix path writes changes back to SKILL.md files, which is more than just scanning and reporting.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

In code files, file writes should be disclosed through a confirmation prompt, user-facing log/print, comment/docstring, or markdown warning unless clearly inherent to the skill's purpose. This script modifies SKILL.md files when --fix is used, but the write happens silently with no explicit notice at the point of action and no surrounding warning about changing user files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The rule 'Add multilingual keywords for non-English users' introduces language-specific behavior guidance, and the example includes Chinese keywords, but the document does not frame this as optional user choice or a justified region-specific requirement. This can create an implicit language/locale policy preference without opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.