{"record":{"id":"d6f6a6f1e6c25946","repo":"vercel/turborepo","slug":"directory-path-contains-potentially-unsafe-charact","errorCode":null,"errorMessage":"Directory path contains potentially unsafe characters: ${dir}","messagePattern":"Directory path contains potentially unsafe characters: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/create-turbo/src/utils/git.ts","lineNumber":36,"sourceCode":"*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# turbo\n.turbo\n\n# vercel\n.vercel\n`;\n\nconst SHELL_METACHARACTERS = /[`$(){}|;&<>!#]/;\n\nfunction assertSafeDirectory(dir: string): void {\n  if (SHELL_METACHARACTERS.test(dir)) {\n    throw new Error(\n      `Directory path contains potentially unsafe characters: ${dir}`\n    );\n  }\n}\n\nfunction git(args: Array<string>, cwd: string): boolean {\n  const result = spawnSync(\"git\", args, { stdio: \"ignore\", cwd });\n  if (result.status !== 0) {\n    throw new Error(`git ${args[0]} failed`);\n  }\n  return true;\n}\n\nfunction isInGitRepository(root: string): boolean {\n  try {\n    git([\"rev-parse\", \"--is-inside-work-tree\"], root);\n    return true;\n  } catch (_) {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/create-turbo/src/utils/git.ts#L18-L54","documentation":"create-turbo runs `tryGitInit(root)` at the end of scaffolding (git init + initial commit), and first calls assertSafeDirectory, which rejects any target path containing shell metacharacters (` $ ( ) { } | ; & < > ! #). This is a command-injection guard on the path that reaches git subprocess invocation; scaffolding aborts with this plain Error before git runs.","triggerScenarios":"Passing create-turbo an installation path or project name whose string contains any of: backtick, $, (, ), {, }, |, ;, &, <, >, !, #. Examples: `npx create-turbo my$app`, a directory like `app(1)`, `c#service`, `foo&bar`, `turbo!(v2)`.","commonSituations":"Copy-pasting a folder name containing special characters; Windows 'Copy of app (2)'-style names; users attempting shell-expansion-like project names; scripted invocations that interpolate unescaped variables into the path.","solutions":["Re-run create-turbo with a project name/path limited to letters, digits, hyphen, underscore, dot, and slash (e.g. `my-app`, `apps/turbo-v2`)","If the special-character name is a hard requirement, scaffold under a safe name first and rename the directory afterwards with `mv`","In scripts, sanitize the interpolated variable before passing it to create-turbo"],"exampleFix":"# before\nnpx create-turbo@latest \"apps/turbo!(v2)\"\n# after\nnpx create-turbo@latest apps/turbo-v2","handlingStrategy":"validation","validationCode":"const SHELL_METACHARACTERS = /[`$(){}|;&<>!#]/;\n\nfunction isSafeDirectory(dir: string): boolean {\n  return !SHELL_METACHARACTERS.test(dir);\n}\n// run before create-turbo / tryGitInit:\nif (!isSafeDirectory(targetDir)) throw new Error('pick an alphanumeric path');","typeGuard":"function isSafeDirectoryName(name: string): boolean {\n  return !/[`$(){}|;&<>!#]/.test(name);\n}","tryCatchPattern":"try {\n  await createApp({ root: targetDir });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('potentially unsafe characters')) {\n    // re-prompt the user for a sanitized name instead of crashing\n    targetDir = sanitize(targetDir); // strip/replace metacharacters, then retry once\n  } else throw err;\n}","preventionTips":["Constrain project names to /^[A-Za-z0-9._-]+$/ in any script that drives create-turbo","Sanitize CI variables before interpolating them into scaffold paths","Scaffold under a safe name and rename with `mv` afterwards if exotic characters are truly required"],"tags":["create-turbo","security","input-validation","git","path-validation"],"backgroundTag":"unsafe-path-characters","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}