nexu-io/open-design · error · SystemExit
path traversal detected in input_images for job {job.get('id
Error message
path traversal detected in input_images for job {job.get('id')} What it means
Raised by path_list after resolving an input_images path: the resolved absolute path does not stay inside run_dir (Path.is_relative_to(run_dir) is False). This is a deliberate path-traversal guard so a manifest cannot reference files outside the run directory.
Source
Thrown at skills/hatch-pet/scripts/generate_pet_images.py:219
manifest["canonical_identity_reference"] = reference
request_path = run_dir / "pet_request.json"
if request_path.exists():
request = json.loads(request_path.read_text(encoding="utf-8"))
request["canonical_identity_reference"] = reference
request_path.write_text(json.dumps(request, indent=2) + "\n", encoding="utf-8")
def path_list(run_dir: Path, job: dict[str, object]) -> list[Path]:
inputs = job.get("input_images")
if not isinstance(inputs, list):
raise SystemExit(f"job {job.get('id')} has invalid input_images")
paths = []
for item in inputs:
if not isinstance(item, dict) or not isinstance(item.get("path"), str):
raise SystemExit(f"job {job.get('id')} has invalid input image entry")
path = (run_dir / item["path"]).resolve()
if not path.is_relative_to(run_dir):
raise SystemExit(f"path traversal detected in input_images for job {job.get('id')}")
if not path.is_file():
raise SystemExit(f"input image for job {job.get('id')} not found: {path}")
paths.append(path)
return paths
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--run-dir", required=True)
parser.add_argument("--model", default="gpt-image-2")
parser.add_argument("--size", default="1024x1024")
parser.add_argument("--states", default="all")
parser.add_argument("--job-id", action="append", default=[])
parser.add_argument("--skip-base", action="store_true")
args = parser.parse_args()
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:View on GitHub (pinned to 5be4028344)
Solutions
- Keep every input_images path relative to run_dir and free of ../ escapes.
- Copy any needed external image into run_dir/references first, then reference it by relative path.
- Avoid symlinks inside run_dir that point outside it; replace them with real files.
- Regenerate the run dir with prepare_pet_run.py, which only writes in-run relative paths.
Example fix
// before (manifest)
"input_images": [
{"path": "/home/user/photos/secret.png", "role": "reference"}
]
// after - copy the file into the run dir and reference relatively
"input_images": [
{"path": "references/reference-01.png", "role": "pet reference"}
] Defensive patterns
Strategy: validation
Validate before calling
def safe_join(run_dir: Path, relative: str) -> Path:
candidate = (run_dir / relative).resolve()
if not candidate.is_relative_to(run_dir):
raise SystemExit(f"path traversal detected: {relative}")
return candidate Type guard
def is_in_run_dir(run_dir: Path, relative: str) -> bool:
return (run_dir / relative).resolve().is_relative_to(run_dir) Prevention
- Never put absolute paths or ../ in manifest path fields; keep everything relative to run_dir.
- Avoid symlinks inside run_dir that point outside it.
- Regenerate the manifest rather than editing paths by hand.
When it happens
Trigger: An input_images entry's path contains ../ that escapes run_dir, or is an absolute path pointing elsewhere on disk (e.g. /etc/passwd or /home/user/secret.png).
Common situations: Hand-editing input_images to point at convenience absolute paths; symlinks inside run_dir that resolve outside it; a manifest copied from another machine whose relative paths now resolve differently.
Related errors
- path traversal detected in prompt_file for job {job_id}
- path traversal detected in output_path for job {job_id}
- invalid brand id: ${input.brandId}
- invalid design system id: ${designSystemId}
- --image path "${rel}" resolves outside the project directory
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/0c954a866dcd9a8f.
Report an issue: GitHub.