{"record":{"id":"0659df482d117b7e","repo":"hashicorp/nomad","slug":"image-path-is-not-in-the-allowed-paths","errorCode":null,"errorMessage":"image_path is not in the allowed paths","messagePattern":"image_path is not in the allowed paths","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/qemu/driver.go","lineNumber":489,"sourceCode":"\thandle.Config = cfg\n\n\tif err := validateEmulator(driverConfig.Emulator, d.config.EmulatorsAllowList); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif err := validateArgs(d.config.ArgsAllowList, driverConfig.Args); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Get the image source\n\tvmPath := driverConfig.ImagePath\n\tif vmPath == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"image_path must be set\")\n\t}\n\tvmID := filepath.Base(vmPath)\n\n\tif !isAllowedImagePath(d.config.ImagePaths, cfg.AllocDir, vmPath) {\n\t\treturn nil, nil, fmt.Errorf(\"image_path is not in the allowed paths\")\n\t}\n\n\t// Parse configuration arguments\n\t// Create the base arguments\n\temulator := \"x86_64\"\n\tif driverConfig.Emulator != \"\" {\n\t\t// COMPAT: TrimPrefix to support full emulator name\n\t\t// which was required in 1.11.1.\n\t\temulator = strings.TrimPrefix(driverConfig.Emulator, \"qemu-system-\")\n\n\t}\n\taccelerator := \"tcg\"\n\tif driverConfig.Accelerator != \"\" {\n\t\taccelerator = driverConfig.Accelerator\n\t}\n\tmachineType := \"pc\"\n\tif driverConfig.MachineType != \"\" {\n\t\tmachineType = driverConfig.MachineType","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/qemu/driver.go#L471-L507","documentation":"The QEMU driver validates, at task start, that the VM image path (image_path) is either inside one of the client's configured 'image_paths' allowlist directories or inside the task's allocation directory. If isAllowedImagePath() rejects the path, StartTask refuses to launch the VM. This is a security guard against arbitrary file access by task authors, since QEMU would otherwise run with whatever disk image the task specifies.","triggerScenarios":"Calling tasks.start (QEMU driver) with driver config image_path pointing to a file outside config.image_paths allowlist and outside the task's alloc dir; empty or mis-scoped image_paths in the client 'plugin.qemu.driver.image_paths' config; using a relative or symlinked path that resolves outside allowed roots.","commonSituations":"Operator forgets to add the image directory to image_paths in the Nomad client config; dev setups using images in /home or /tmp while allowlist points elsewhere; images mounted at a different path on the client node than in the allowlist; path typo or symlink chain escaping the allowlist.","solutions":["Add the directory containing the VM image to the client QEMU driver config: plugin \"qemu\" { driver \"qemu\" { image_paths = [\"/srv/images\"] } } and restart the Nomad client.","Place the image inside the task's allocation directory (e.g. download it with an artifact block) which is always allowed.","Verify the image_path in the task's driver config exactly matches a real file under one of the allowed roots (check for typos and symlinks)."],"exampleFix":"// task config: before\nimage_path = \"/home/ops/alpine.qcow2\"\n// after (client hcl: plugin \"qemu\" { config { image_paths = [\"/srv/images\"] } })\nimage_path = \"/srv/images/alpine.qcow2\"","handlingStrategy":"validation","validationCode":"// before submitting, confirm image lives under an allowed root\nconst allowedRoots = [\"/srv/images\"]; // must match client config image_paths\nfunction isAllowedImagePath(root, allocDir, p) {\n  const abs = require(\"path\").resolve(p);\n  return [allocDir, ...root].some\n    ? [allocDir, ...allowedRoots].some((r) => abs.startsWith(require(\"path\").resolve(r) + require(\"path\").sep))\n    : false;\n}","typeGuard":"function hasAllowedImagePath(cfg) {\n  return typeof cfg.image_path === \"string\" && cfg.image_path.length > 0 &&\n    allowedRoots.some((r) => require(\"path\").resolve(cfg.image_path).startsWith(require(\"path\").resolve(r) + require(\"path\").sep));\n}","tryCatchPattern":"try {\n  await nomad.jobs.startTask(cfg);\n} catch (e) {\n  if (String(e.message).includes(\"image_path is not in the allowed paths\")) {\n    console.error(`Move ${cfg.image_path} under an image_paths root or add its dir to client config`);\n  }\n  throw e;\n}","preventionTips":["Keep VM images in a single dedicated directory and register it in client image_paths.","Prefer artifact blocks so images land in the alloc dir (always allowed).","Avoid symlinks for images; resolve paths before comparing against allowlist.","After changing client config image_paths, restart the Nomad client agent."],"tags":["qemu","security","path-validation","nomad"],"backgroundTag":"path-not-allowed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}