chatboxai/chatbox · error · Error

Invalid skill name: path traversal not allowed

Error message

Invalid skill name: path traversal not allowed

What it means

Thrown by the skills:execute-script IPC handler when skillName contains '..', '/', or '\\'. This is a path-traversal guard preventing the constructed scriptPath (path.join(skillsDir, skillName, 'scripts', scriptName)) from escaping the skills directory. It is the first of two layers — a syntactic check followed by a realpath containment check (error 107).

Source

Thrown at src/main/skills/ipc-handlers.ts:178

      return { success: false, error: error instanceof Error ? error.message : 'Unknown error' }
    }
  })

  ipcMain.handle(
    'skills:execute-script',
    async (
      _event,
      params: { skillName: string; scriptName: string; args?: string[] }
    ): Promise<{ success: boolean; stdout: string; stderr: string; exitCode: number | null }> => {
      const { skillName, scriptName, args = [] } = params

      try {
        if (!skillName || !scriptName) {
          throw new Error('Skill name and script name are required')
        }

        if (skillName.includes('..') || skillName.includes('/') || skillName.includes('\\')) {
          throw new Error('Invalid skill name: path traversal not allowed')
        }

        if (scriptName.includes('..') || scriptName.includes('/') || scriptName.includes('\\')) {
          throw new Error('Invalid script name: path traversal not allowed')
        }

        const skillsDir = getSkillsDir()
        const scriptPath = path.join(skillsDir, skillName, 'scripts', scriptName)
        if (!fs.existsSync(scriptPath)) {
          throw new Error(`Script not found: ${scriptName}`)
        }
        const resolvedSkillsDir = fs.realpathSync(skillsDir)
        const resolvedScriptPath = fs.realpathSync(scriptPath)
        if (!resolvedScriptPath.startsWith(`${resolvedSkillsDir}${path.sep}`)) {
          throw new Error('Script path escapes skills directory')
        }

        const scriptDir = path.dirname(resolvedScriptPath)

View on GitHub (pinned to 81571269ad)

Solutions

  1. Use a flat skill identifier (alphanumeric, dash, underscore only) — never allow slashes in skill names.
  2. Validate skillName against a strict allowlist pattern in the renderer before invoking the IPC.
  3. If a nested path is genuinely needed, redesign the skill layout to be flat under skills/{name}/scripts/.

Example fix

// before
if (skillName.includes('..') || skillName.includes('/') || skillName.includes('\\')) {
  throw new Error('Invalid skill name: path traversal not allowed')
}

// after — single strict allowlist regex covers traversal, slashes, and hidden dirs
const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/
if (!SAFE_NAME.test(skillName)) {
  throw new Error(`Invalid skill name: ${skillName}`)
}
Defensive patterns

Strategy: validation

Validate before calling

const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/
function isSafeSkillName(name: string): boolean {
  return SAFE_NAME.test(name)
}
if (!isSafeSkillName(skillName)) {
  throw new Error(`Invalid skill name: ${skillName}`)
}

Type guard

function isSafeName(name: unknown): name is string {
  return typeof name === 'string' && /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(name)
}

Try / catch

// The handler returns { success: false, stderr: message } for all thrown errors,
// so callers check the result envelope rather than catching.
const result = await ipcRenderer.invoke('skills:execute-script', params)
if (!result.success && /path traversal/i.test(result.stderr)) {
  showToast('Skill name contains invalid characters')
}

Prevention

When it happens

Trigger: A renderer (or any IPC client) sends skillName like '../', '..\\', 'a/../../../etc', or 'foo/bar'. Because path.join resolves these segments, the resulting path would point outside the skills directory without this guard.

Common situations: Malicious or buggy IPC payload; a skill whose name legitimately contains a slash is rejected (by design); testing the handler with crafted inputs. The realpath check (107) is the backstop if this string check is bypassed via symlinks.

Related errors


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/2cfec44fbb99d211. Report an issue: GitHub.