Mintplex-Labs/anything-llm · error · Error

Access denied - symlink target outside allowed directories.

Error message

Access denied - symlink target outside allowed directories.

What it means

Thrown by validatePath() after fs.realpath() resolves the requested path to a real target that lies OUTSIDE the allowed directories. This catches symlink-escape attempts where the path itself appears inside the workspace but ultimately points elsewhere. Distinct from 394, which fires before realpath; this fires after, on the resolved target.

Source

Thrown at server/utils/agents/aibitat/plugins/filesystem/lib.js:444

      console.log(
        `[validatePath] Access denied - path outside allowed directories: ${absolute} not in ${this.#allowedDirectories.join(", ")}`
      );
      throw new Error(`Access denied - path outside allowed directories.`);
    }

    try {
      const realPath = await fs.realpath(absolute);
      const normalizedReal = this.#normalizePath(realPath);
      if (
        !this.#isPathWithinAllowedDirectories(
          normalizedReal,
          this.#allowedDirectories
        )
      ) {
        console.log(
          `[validatePath] Access denied - symlink target outside allowed directories: ${realPath} not in ${this.#allowedDirectories.join(", ")}`
        );
        throw new Error(
          `Access denied - symlink target outside allowed directories.`
        );
      }
      return realPath;
    } catch (error) {
      if (error.code === "ENOENT") {
        const parentDir = path.dirname(absolute);
        try {
          const realParentPath = await fs.realpath(parentDir);
          const normalizedParent = this.#normalizePath(realParentPath);
          if (
            !this.#isPathWithinAllowedDirectories(
              normalizedParent,
              this.#allowedDirectories
            )
          ) {
            console.log(
              `[validatePath] Access denied - parent directory outside allowed directories: ${realParentPath} not in ${this.#allowedDirectories.join(", ")}`

View on GitHub (pinned to 526360e320)

Solutions

  1. Remove or rewrite the offending symlink so its target is within an allowed directory.
  2. Audit the workspace for symlinks pointing outside (find -type l).
  3. Do not create symlinks in the workspace that escape the sandbox.
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require("fs/promises");
async function assertSymlinkTargetInside(p, allowedDirs) {
  const st = await fs.lstat(p);
  if (st.isSymbolicLink()) {
    const target = await fs.realpath(p);
    if (!allowedDirs.some((d) => target.startsWith(path.resolve(d))))
      throw new Error(`Symlink ${p} escapes workspace`);
  }
}

Try / catch

try { await filesystem.validatePath(p); }
catch (e) {
  if (e.message.includes("symlink target outside")) { /* remove the offending link */ }
  else throw e;
}

Prevention

When it happens

Trigger: A path inside the allowed workspace that is a symlink whose target resolves outside the workspace (e.g., workspace/secret -> /etc). The normalized requested path passes the first check, but realpath reveals the true destination is forbidden.

Common situations: A malicious or accidental symlink planted in the workspace pointing to system files; a symlink chain that eventually leaves the workspace; an agent or user creating a link to shortcut access to outside files.

Understand the failure class

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/729782da75dd8bd8. Report an issue: GitHub.