Back to skill

Security audit

agent-context-diet

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent purpose, but its bulk skill-modification script lacks enough filesystem containment for safe installation without review.

Install only if you are comfortable letting this skill modify installed skill directories. Before using --apply, run the dry run, set --root to a narrowly chosen skills folder, inspect the target tree for symlinks, keep backups outside the skills root, and avoid the rm -rf rollback example unless you have listed the exact files to remove.

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

Error
Location
scripts/split_skills.py:138
Finding

Symlink-Based Write Outside the Skill References Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/split_skills.py, lines 138–152 and 167–170
Vulnerability Type: Symlink following leading to arbitrary file overwrite
Risk Level: High

Technical Analysis

The script derives output filenames from headings in a skill's SKILL.md. During collision checking, it uses Path.exists():

python
for i, ch in enumerate(chunks, 1):
    base = slug(ch[0][0]) + (f"-{i}" if i > 1 else "")
    target, n = refs / f"{base}.md", 2
    body = "".join(t for _, t in ch)
    # unique name within the run: two sections with the SAME heading must not
    # collapse into one file with one table-of-contents entry
    while target.name in used_names or (target.exists()
                                        and target.read_text(encoding="utf-8") != body):
        target = refs / f"{base}-{n}.md"
        n += 1
    used_names.add(target.name)
    span = f"{ch[0][0][:40]} … {ch[-1][0][:40]}" if len(ch) > 1 else ch[0][0][:60]
    toc.append(f"* `references/{target.name}` — {span}\n")
    files.append((target.name, body))

The selected destinations are subsequently written without checking for symbolic links or verifying that their resolved paths remain inside the intended references directory:

python
refs.mkdir(parents=True, exist_ok=True)
for name, body in files:
    (refs / name).write_text(body, encoding="utf-8")
skill_md.write_text(new_md, encoding="utf-8")

Path.exists() returns false when a path is a dangling symbolic link. Consequently, a dangling link at a predicted generated filename is treated as an unused destination. Path.write_text() then follows the symbolic link and creates or overwrites its target.

The generated filename is predictable because it is derived from an attacker-controlled H2 heading through slug(). The script does not resolve the destination, enforce containment, reject symbolic links, or use a no-follow file-crea ...[truncated 1616 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject symbolic links for the skill directory, references directory, and every destination component before writing.
  2. Resolve the intended output directory and candidate destination, then verify containment:
    python
    refs_real = refs.resolve(strict=True)
    destination = refs / name
    resolved_parent = destination.parent.resolve(strict=True)
    if resolved_parent != refs_real:
        raise ValueError("Output path escapes the references directory")
    
  3. Create output files using descriptor-based, no-follow semantics, such as os.open() with O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, and write through the returned descriptor. Handle platforms without O_NOFOLLOW explicitly rather than silently falling back.
  4. Do not rely on a separate exists() check before writing because that also creates a time-of-check/time-of-use race. Perform validation and exclusive creation as one atomic operation.
  5. Open the references directory as a trusted directory descriptor and use directory-relative operations where supported, preventing path replacement between validation and creation.
  6. Add regression tests covering dangling symlinks, links to existing external files, replacement of references with a symlink, and concurrent destination replacement. The expected behavior should be a safe failure without modifying any external target.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (12)

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The document title and the entire skill description are written in Russian, with no indication that other languages are supported or that Russian is optional. This creates a natural-language locale constraint that may violate organizational language policy when users have not explicitly opted into Russian.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill explicitly instructs use of terminal, file, and python-based workflows that can read, write, and modify skill directories, but it does not declare a scoped permission model such as allowed-tools or path restrictions. In an agent environment, this increases the chance that the skill is invoked with broader-than-necessary filesystem or shell access, enabling unintended modification of user files or neighboring skills if variables like SKILLS_DIR are mis-set.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The rollback section includes rm -rf <путь>/<имя>/references/<новые-файлы> without guardrails, validation steps, or an explicit warning that an incorrect path expansion can irreversibly delete unintended files. In an agent-assisted workflow, placeholders or variables may be substituted incorrectly, making this more dangerous than a manual expert-only command because the agent could execute deletion with elevated confidence but insufficient context.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code file contains user-facing natural-language strings and documentation that effectively force a single language/locale. The policy allows locale constraints only when users are given a choice or when the restriction is clearly documented and justified; neither is present here.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring is entirely in Russian and presents the usage and behavior descriptions only in that language. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless clearly justified as region-specific, which is not stated here.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/test_split_skills.py (reported line 27)May include surrounding context.

python
def run(*args, **kw):
    return subprocess.run([PY, str(SCRIPT), *map(str, args)], capture_output=True,
                          text=True, **kw)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file's instructions and examples are presented entirely in Russian, which imposes a specific language on the user. The policy allows fixed locale only when the constraint is justified or when users are offered a choice, neither of which is stated here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring, CLI descriptions, and user-facing output are all written only in Russian, which imposes a specific language on users without offering an alternative or documenting a justified locale restriction. This matches the policy category for language or locale constraints in natural-language content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.