Back to skill

Security audit

Markdown Linter

Security checks for vulnerabilities and agentic risk

Overview

This Markdown linter mostly matches its purpose, but its recursive scan can follow directory symlinks outside the requested workspace and may read or report out-of-scope Markdown files.

Review before installing if you work in repositories that may contain symlinks to private directories or very large directory trees. Use it only on trusted workspaces, and prefer a version that skips symlinks or enforces root boundaries and recursion limits.

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
index.js:17
Finding

Directory Symlink Traversal and Recursive Denial of Service

Content
View full analysis

Vulnerability Details

File Location: index.js, lines 17-30
Vulnerability Type: Unrestricted symlink traversal and unbounded recursive directory scanning
Risk Level: Medium

Vulnerable Code

javascript
try {
  const list = fs.readdirSync(dir);
  for (const file of list) {
    if (ignore.includes(file)) continue;
    const filePath = path.join(dir, file);
    let stat;
    try {
      stat = fs.statSync(filePath);
    } catch (e) {
      continue;
    }
    
    if (stat && stat.isDirectory()) {
      results = results.concat(findMarkdownFiles(filePath, ignore));

Technical Analysis

The recursive scanner uses fs.statSync() to inspect workspace entries. This function follows symbolic links, so a symbolic link to a directory is treated as the target directory rather than as a link. The code neither verifies that the canonical target remains under the requested scan root nor tracks previously visited directories.

Consequently, a symbolic link placed inside the scanned workspace can redirect traversal to an arbitrary directory accessible to the process. If the link points to an ancestor or otherwise creates a directory cycle, the same directory tree can be traversed repeatedly. The synchronous, unbounded recursion may then exhaust stack, CPU, or memory resources.

Attack Path

  1. An attacker with the ability to add files or symbolic links to the scanned workspace creates a directory symlink.
  2. The symlink points either outside the workspace to a sensitive, readable directory or back to an ancestor directory to form a cycle.
  3. A user or agent invokes scan() against the affected workspace.
  4. fs.statSync() follows the symlink and reports its target as a directory.
  5. findMarkdownFiles() recursively enters the target without checking its canonical path.
  6. For an external target, the scanner reads Markdown files outside the intended root and returns file ...[truncated 736 chars]
Remediation
View remediation

Remediation Suggestions

  1. Use fs.lstatSync() when inspecting directory entries and skip symbolic links by default:

    javascript
    const stat = fs.lstatSync(filePath);
    if (stat.isSymbolicLink()) continue;
    
  2. Canonicalize the scan root with fs.realpathSync() and verify that every traversed path remains within that root. Path-boundary checks should use path.relative() rather than a simple string-prefix comparison.

  3. Maintain a set of visited canonical directory paths, or device-and-inode identifiers, and refuse to revisit a directory. This prevents cycles even if symbolic-link traversal is intentionally enabled.

  4. Add configurable maximum traversal depth and file-count limits to bound CPU, memory, and filesystem usage.

  5. Return root-relative paths where possible so reports do not unnecessarily disclose absolute filesystem locations.

  6. Add tests covering symlinks to external directories, links to ancestor directories, directory cycles, depth limits, and canonical root-boundary enforcement.

Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code largely matches the declared purpose of scanning Markdown files in the workspace and checking local links/file references. It recursively finds .md files, reads them, extracts inline Markdown links, and verifies whether local targets exist. However, the description overstates the functionality by claiming 'basic syntax issues' validation, which the code does not implement. It also implies broader missing file reference validation, while the implementation only checks standard inline link targets and does not validate other Markdown constructs or syntax problems. There are no concerning undeclared capabilities such as network access, data exfiltration, or modification of files.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.