Back to skill

Security audit

Skill Sync

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly transparent about managing local AI-agent skills, but its restore path can apply untrusted backup manifests and mutate files outside the intended skill roots.

Install only if you need cross-agent local skill management and are comfortable with a tool that can scan and rewrite multiple skill directories. Always run preview commands first, use --apply only after checking the planned paths, and do not restore from backup runs or manifests you did not generate and trust.

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/skill_sync.py:1193
Finding

Path Traversal and Unrestricted Filesystem Operations Through Restore Manifests

Content
View full analysis
Path: if run_id == "latest": latest = backup_root / "latest" if latest.is_symlink(): return latest.resolve(strict=False) raise SystemExit("No latest backup run is available") run_dir = backup_root / run_id if not run_dir.is_dir(): raise SystemExit(f"Backup run not found: {run_id}") return run_dir def restore_run(run_dir: Path, apply: bool) -> dict: manifest_path = run_dir / "manifest.json" if not manifest_path.is_file(): raise SystemExit(f"Missing manifest: {manifest_path}") manifest = read_json(manifest_path) actions = manifest.get("actions", []) if not apply: return manifest for action in reversed(actions): destination = Path(action["path"]) if destination.is_symlink(): destination.unlink() elif destination.exists(): raise SystemExit( f"Restore blocked because destination is no longer a symlink: {destination}" ) backup_path = action.get("backup_path") if backup_path: source_backup = Path(backup_path) if not source_backup.exists() and not source_backup.is_symlink(): raise SystemExit(f"Missing backup payload: {source_backup}") destination.parent.mkdir(parents=True, exist_ok=True) shutil.move(str(source_backup), str(destination)) ``` ### Technical Analysis The value supplied through `--restore` is combined with `backup_root` without validating that it is a generated run identifier or that the resulting directory remains inside the configured backup directory. A value containing `..` components can escape `backup_root`. An absolute path ...[truncated 2917 chars]
Remediation
View remediation
/originals`. - Require every destination to match an approved Skill root recorded by the application. - Reject relative, malformed, duplicate, or unexpected destination paths. - Do not use unrestricted absolute paths directly from manifest data. 4. **Validate the complete manifest before applying any action** - Enforce a strict schema and supported manifest version. - Validate action types, required fields, path types, and expected source/destination relationships. - Complete all validation before performing the first filesystem mutation to avoid partial application. 5. **Add manifest integrity protection** - Store a cryptographic digest or authenticated signature when creating a restore manifest. - Verify integrity before applying restoration. - Ensure backup directories and manifests are writable only by the owning user. 6. **Use safer restore reconstruction** - Derive backup payload paths from validated destinations rather than accepting arbitrary `backup_path` values from JSON. - Record approved roots in trusted run metadata and reject destinations outside those roots. 7. **Add regression tests** - Test rejection of absolute restore identifiers. - Test rejection of `../` traversal. - Test a `latest` symlink resolving outside the backup root. - ...[truncated 193 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/skill_sync.py

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- It only auto-links portable directory-based skills that contain `SKILL.md`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- It only auto-links portable directory-based skills that contain `SKILL.md`.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_skill_sync_cli.py (reported line 29)May include surrounding context.

python
class SkillSyncCliTests(unittest.TestCase):
    def run_cli(self, machine_root: Path, *args: str) -> subprocess.CompletedProcess[str]:
        env = os.environ.copy()
        env.update(
            {
                "HOME": str(machine_root),

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 · README.md (reported line 13)May include surrounding context.

md
- pick a canonical source automatically
- replace duplicate copies with symlinks
- back up every replaced install so you can restore it later
- export a portable layout manifest and recreate that topology on another machine

## Who This Is For

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README instructs users to run --apply operations that modify installed skill directories, but it does not place an immediate, explicit warning near those commands that existing directories may be moved and replaced with symlinks. In a tool that rewrites filesystem layout across multiple agent roots, that omission can lead to accidental destructive changes or confusing state if users apply commands without fully understanding the consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The convergence application example shows an apply command without a clear nearby caution that it can replace existing skill directories with symlinks under a canonical root. Because the documented behavior changes ownership/layout across user skill roots, insufficient warning increases the risk of unintended filesystem modifications and operational breakage.

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 · README.md (reported line 212)May include surrounding context.

md
### Cross-Machine Migration

Use `--export-manifest` to save the desired symlink topology and `--import-manifest` to recreate that topology elsewhere.

The manifest records:

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
85% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · install.sh (reported line 20)May include surrounding context.

sh
Targets:
  --codex       Install into ~/.codex/skills
  --agents      Install into ~/.agents/skills
  --claude      Install into ~/.claude/skills
  --opencode    Install into ~/.config/opencode/skills
  --openclaw    Install into ~/.openclaw/skills

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 · tests/test_skill_sync_cli.py (reported line 41)May include surrounding context.

python
"SKILL_SYNC_BACKUP_ROOT": str(machine_root / "backups"),
            }
        )
        return subprocess.run(
            [sys.executable, str(SCRIPT_PATH), *args],
            cwd=str(REPO_ROOT),
            env=env,