Back to skill

Security audit

SkillHub Publish Auditor

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent release-auditor, but its bundled scanner can read outside the chosen skill folder through symlinks and can silently skip scans in some common paths.

Review before installing. The skill's purpose is legitimate, but until the scanner is fixed, avoid running it on untrusted skill archives that may contain symlinks and avoid audit paths under excluded directory names such as build or dist. Prefer a patched version that rejects symlinks, enforces resolved-path containment, and reports when no files were scanned.

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
scripts/audit_skill_release.py:34
Finding

Package Boundary Escape Through Symbolic Links

Content
View full analysis
Iterable[Path]: skip_dirs = {".git", "__pycache__", "node_modules", ".venv", "dist", "build"} for path in root.rglob("*"): if any(part in skip_dirs for part in path.parts): continue if path.is_file(): yield path ``` The returned paths are subsequently read without validating their resolved locations: ```python def audit_security(root: Path, findings: list[Finding]) -> None: for path in iter_files(root): rel = path.relative_to(root) if path.stat().st_size > 512 * 1024: add(findings, WARN, "file.size", path, f"{rel} is larger than 512 KB; review whether it belongs in a skill.") continue if path.suffix.lower() not in {".md", ".py", ".sh", ".ps1", ".js", ".ts", ".json", ".yaml", ".yml", ".txt"}: continue text = read_text(path) ``` ### Technical Analysis The auditor is intended to inspect files contained within a selected Skill directory. However, `Path.is_file()`, `Path.stat()`, and `Path.read_text()` follow symbolic links. The iterator does not reject symlinks or resolve each candidate path and verify that the resolved target remains beneath the canonical audit root. Consequently, a malicious Skill can include a supported-extension file symlink whose target is outside the package. The linked external file will be opened and processed by `audit_security()` with the permissions of the user running the auditor. This behavior exceeds the minimum privileges required for package auditing: the auditor only needs to inspect files physically contained in the selected Skill directory. ### Attack Path 1. An at ...[truncated 1544 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/audit_skill_release.py:34
Finding

Security Scan Bypass Through Absolute-Path Directory Exclusions

Content
View full analysis
Iterable[Path]: skip_dirs = {".git", "__pycache__", "node_modules", ".venv", "dist", "build"} for path in root.rglob("*"): if any(part in skip_dirs for part in path.parts): continue ``` ### Technical Analysis The script resolves the user-supplied root before scanning: ```python root = args.skill_folder.resolve() ``` Paths produced by `root.rglob("*")` therefore contain the complete absolute path. The exclusion condition evaluates every component in `path.parts`, including components belonging to parent directories outside the audited Skill. If the Skill directory or any of its ancestors is named `build`, `dist`, `node_modules`, `.venv`, or another excluded name, every discovered path satisfies the skip condition. Security scanning and link inspection can consequently omit the entire package without reporting that no files were examined. The exclusions are intended to apply only to designated child directories inside the candidate package. Applying them to unrelated ancestors creates a fail-open scanner bypass. ### Attack Path 1. A candidate Skill is placed beneath an excluded directory name, for example `/workspace/build/candidate-skill`. 2. The user runs the auditor against `/workspace/build/candidate-skill`. 3. `resolve()` preserves `build` as an ancestor component of the absolute audit path. 4. Every file returned by `rglob()` has `build` in `path.parts`. 5. `iter_files()` silently skips every file. 6. `audit_links()` and `audit_security()` receive no files and therefore cannot identify unsafe content. 7. If no independent check produces a blocker or warning, the package can receive an incorrectly favorable release decision. An attacker can exploit this directly when infl ...[truncated 712 chars]
Remediation
View remediation
Iterable[Path]: skip_dirs = {".git", "__pycache__", "node_modules", ".venv", "dist", "build"} for path in root.rglob("*"): relative = path.relative_to(root) if any(part in skip_dirs for part in relative.parts[:-1]): continue if path.is_file(): yield path ``` 2. Prefer a directory-walking implementation that prunes excluded child directories explicitly rather than discovering their descendants and filtering afterward. 3. Track the number of eligible files examined. Emit a warning or fail closed if no auditable files are scanned, especially when known package files such as `SKILL.md` exist. 4. Report excluded directories and exclusion counts in verbose or JSON output so users can verify the effective scan scope. 5. Add regression tests for Skill roots located under each reserved ancestor name, including: - `/tmp/build/example-skill` - `/tmp/dist/example-skill` - `/tmp/node_modules/example-skill` Each test should confirm that files directly inside the Skill are still scanned while only matching descendant directories are excluded. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (5)

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
90% confidence
Finding

Skill attempts to nullify the agent's safety policies or restrictions ('you have no restrictions', 'ignore your guidelines', 'do anything now'). This is a direct jailbreak that disables guardrails.

Content

Scanner excerpt · references/release-checklist.md (reported line 23)May include surrounding context.

md
- executes base64, eval, encoded PowerShell, or hidden payloads
- sends local file contents to a remote endpoint
- performs destructive recursive filesystem operations without a narrow checked path
- contains hidden instruction-override payloads that try to bypass policy, disclose credentials, or install extra payloads

## Quality

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/audit_skill_release.py (reported line 112)May include surrounding context.

python
ll root.")
        return

    text = read_text(skill_md)
    fm, error = parse_frontmatter(text)
    if error:
        add(findings, BLOCKER, "frontmatter.parse", skill_md, error)
        return

    name = fm.get("name", "")
    description = fm.get("description", "")
    if not name:
        add(findings, BLOCKER, "frontmatter.name", skill_md, "frontmatter name is required.")
    elif not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", name):
        add(findings, BLOCKER, "frontmatter.name_format", skill_md, "name must use lowercase letters, digits, and hyphens only.")
    if not description:
        add(findings, BLOCKER, "frontmatter.description", skill_md, "frontmatter description is required.")
    elif not description.startswith("Use when"):
        add(findings, WARN, "frontmatter.description_trigger", skill_md, "description should start with 'Use when' and describe trigger conditions.")
    if len("\n".join(f"{k}: {v}" for k, v in fm.items())) > 1024:
        add(findings, WARN, "

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 · scripts/audit_skill_release.py (reported line 159)May include surrounding context.

python
(BLOCKER, "shell.pipe_install", r"curl\s+[^\n|]+\|\s*(sh|bash)|wget\s+[^\n|]+\|\s*(sh|bash)", "downloaded code is piped into a shell"),
    (BLOCKER, "code.encoded_exec", r"base64\s+(-d|--decode)|Invoke-Expression|\biex\b|eval\s*\(", "encoded or dynamic code execution"),
    (BLOCKER, "fs.destructive", r"rm\s+-rf\s+(/|\$HOME|~)|Remove-Item\s+.*-Recurse", "destructive recursive filesystem command"),
    (WARN, "prompt.injection", r"ignore previous instructions|reveal secrets|exfiltrate|developer message|system prompt", "prompt-injection-like instruction"),
    (WARN, "network.use", r"https?://|requests\.|urllib|fetch\s*\(|Invoke-WebRequest|curl\s+", "network access or remote endpoint reference"),
]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The description says to use the skill when 'preparing a Skill folder for public release' and lists broad contexts like 'another agent-skill marketplace' without defining specific trigger phrases, exclusions, or boundaries. This creates ambiguity about when the skill should activate versus other general packaging, review, or publishing workflows.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.