Skip to content

OpenSkills Security Explained

What You'll Learn

  • Understand OpenSkills's three-layer security protection mechanism
  • Learn the principles and protection methods for path traversal attacks
  • Master symlink security handling approaches
  • Recognize ReDoS risks in YAML parsing and protection measures

Your Current Challenges

You might have heard that "local execution is safer," but aren't sure what specific security protections exist. Or you're worried when installing skills:

  • Will files be written to system directories?
  • Could symbolic links pose security risks?
  • Are there vulnerabilities when parsing YAML in SKILL.md?

When to Use This Approach

When you need to:

  • Deploy OpenSkills in an enterprise environment
  • Audit OpenSkills security
  • Evaluate skill management solutions from a security perspective
  • Address technical reviews from security teams

Core Concepts

OpenSkills security design follows three principles:

Three-Layer Security Protection

  1. Input Validation - Validate all external inputs (paths, URLs, YAML)
  2. Isolated Execution - Ensure operations are within expected directories
  3. Secure Parsing - Prevent parser vulnerabilities (ReDoS)

Local execution + no data upload + input validation + path isolation = secure skill management

Path Traversal Protection

What is Path Traversal Attack

Path Traversal attacks refer to an attacker using sequences like ../ to access files outside the intended directory.

Example: Without protection, an attacker might try:

bash
# Attempt to install to system directory
openskills install malicious/skill --target ../../../etc/

# Attempt to overwrite configuration file
openskills install malicious/skill --target ../../../../.ssh/

OpenSkills Protection Mechanism

OpenSkills uses the isPathInside function to verify that the installation path must be within the target directory.

Source location: src/commands/install.ts:71-78

typescript
function isPathInside(targetPath: string, targetDir: string): boolean {
  const resolvedTargetPath = resolve(targetPath);
  const resolvedTargetDir = resolve(targetDir);
  const resolvedTargetDirWithSep = resolvedTargetDir.endsWith(sep)
    ? resolvedTargetDir
    : resolvedTargetDir + sep;
  return resolvedTargetPath.startsWith(resolvedTargetDirWithSep);
}

How it works:

  1. Use resolve() to resolve all relative paths to absolute paths
  2. Normalize the target directory to ensure it ends with a path separator
  3. Check if the target path starts with the target directory

Installation validation (src/commands/install.ts:257-260):

typescript
if (!isPathInside(targetPath, targetDir)) {
  console.error(chalk.red('Security error: Installation path outside target directory'));
  process.exit(1);
}

Verify Protection Effectiveness

Test scenario: Attempt path traversal attack

bash
# Normal installation (succeeds)
openskills install anthropics/skills

# Attempt to use ../ (fails)
openskills install malicious/skill --target ../../../etc/
# Security error: Installation path outside target directory

You should see: Any installation attempt to escape the target directory is rejected, showing a security error.

Symbolic Links (Symlinks) are shortcuts to other files or directories. Improper handling can lead to:

  1. Information disclosure - Attackers create symlinks pointing to sensitive files
  2. File overwrite - Symlinks point to system files, which get overwritten during installation
  3. Circular references - Symlinks point to themselves, causing infinite recursion

Dereferencing During Installation

OpenSkills uses dereference: true when copying files to dereference symlinks, directly copying the target file.

Source location: src/commands/install.ts:262

typescript
cpSync(skillDir, targetPath, { recursive: true, dereference: true });

Effect:

  • Symlinks are replaced with actual files
  • The symlink itself is not copied
  • Avoids overwriting files pointed to by symlinks

OpenSkills supports symlinked skills but checks if they are broken.

Source location: src/utils/skills.ts:10-25

typescript
function isDirectoryOrSymlinkToDirectory(entry: Dirent, parentDir: string): boolean {
  if (entry.isDirectory()) {
    return true;
  }
  if (entry.isSymbolicLink()) {
    try {
      const fullPath = join(parentDir, entry.name);
      const stats = statSync(fullPath); // statSync follows symlinks
      return stats.isDirectory();
    } catch {
      // Broken symlink or permission error
      return false;
    }
  }
  return false;
}

Security features:

  • Use statSync() to follow symlinks and check the target
  • Broken symlinks are skipped (catch block)
  • No crashes, silent handling

Use Cases

Symlink support allows you to:

  • Use skills directly from git repositories (no copying needed)
  • Sync modifications during local development
  • Share skill libraries across multiple projects

YAML Parsing Security

ReDoS Risk

Regular Expression Denial of Service (ReDoS) refers to maliciously crafted inputs causing exponential match times for regex patterns, consuming CPU resources.

OpenSkills needs to parse the YAML frontmatter in SKILL.md:

yaml
---
name: skill-name
description: Skill description
---

Non-Greedy Regex Protection

OpenSkills uses non-greedy regular expressions to avoid ReDoS.

Source location: src/utils/yaml.ts:4

typescript
export function extractYamlField(content: string, field: string): string {
  const match = content.match(new RegExp(`^${field}:\\s*(.+?)$`, 'm'));
  return match ? match[1].trim() : '';
}

Key points:

  • +? is a non-greedy quantifier, matching the shortest possible
  • ^ and $ anchor to line start and end
  • Only matches a single line, avoiding complex nesting

Incorrect example (greedy matching):

typescript
// ❌ Dangerous: + will greedily match, potentially encountering backtracking explosion
new RegExp(`^${field}:\\s*(.+)$`, 'm')

Correct example (non-greedy matching):

typescript
// ✅ Safe: +? is non-greedy, stops at the first newline
new RegExp(`^${field}:\\s*(.+?)$`, 'm')

File Permissions and Source Verification

Inheriting System Permissions

OpenSkills doesn't manage file permissions; it directly inherits the operating system's permission controls:

  • Files are owned by the user running OpenSkills
  • Directory permissions follow the system umask settings
  • Permission management is unified by the filesystem

Source Verification for Private Repositories

When installing from private git repositories, OpenSkills relies on git's SSH key verification.

Source location: src/commands/install.ts:167

Recommendation

Ensure your SSH key is configured correctly and added to the git server's authorized key list.

Security of Local Execution

OpenSkills is a purely local tool with no network communication (except for cloning git repositories):

No Data Upload

OperationData Flow
Install skillGit repository → Local
Read skillLocal → Standard output
Sync AGENTS.mdLocal → Local file
Update skillGit repository → Local

Privacy Protection

  • All skill files are stored locally
  • AI agents read through the local filesystem
  • No cloud dependencies or telemetry collection

Difference from Marketplace

OpenSkills doesn't depend on Anthropic Marketplace; it runs entirely locally.

Lesson Summary

OpenSkills's three-layer security protection:

Security LayerProtection MeasureSource Location
Path Traversal ProtectionisPathInside() verifies path is within target directoryinstall.ts:71-78
Symlink Securitydereference: true dereferences symlinksinstall.ts:262
YAML Parsing SecurityNon-greedy regex +? prevents ReDoSyaml.ts:4

Remember:

  • Path traversal attacks access files outside intended directories through ../ sequences
  • Symlinks need dereferencing or checking to avoid information disclosure and file overwrites
  • YAML parsing uses non-greedy regex to avoid ReDoS
  • Local execution + no data upload = higher privacy and security

Up Next

In the next lesson, we'll learn Best Practices

You will learn:

  • Best practices for project configuration
  • Team collaboration solutions for skill management
  • Tips for multi-agent environments
  • Common pitfalls and how to avoid them

Appendix: Source Code Reference

Click to expand source code locations

Updated: 2026-01-24

FeatureFile PathLine Numbers
Path traversal protectionsrc/commands/install.ts71-78
Installation path checksrc/commands/install.ts257-260
Symlink dereferencingsrc/commands/install.ts262
Update path checksrc/commands/update.ts156-172
Symlink checksrc/utils/skills.ts10-25
YAML parsing securitysrc/utils/yaml.ts4

Key functions:

  • isPathInside(targetPath, targetDir): Verify target path is within target directory (prevent path traversal)
  • isDirectoryOrSymlinkToDirectory(entry, parentDir): Check if directory or symlink points to directory
  • extractYamlField(content, field): Use non-greedy regex to extract YAML field (prevent ReDoS)

Changelog: