abi/screenshot-to-code · error · InvalidSetNameError

Invalid image path: {filename!r}

Error message

Invalid image path: {filename!r}

What it means

resolve_set_image_path raises InvalidSetNameError("Invalid image path") when the realpath of inputs_dir + basename(filename) escapes the realpath'd inputs directory. This is the path-traversal guard: although basename() already strips directory components, a symlinked file inside inputs/ whose target lives outside would still resolve outside, and the prefix check catches that. It fires when the resolved path does not start with realpath(inputs_dir) + os.sep.

Source

Thrown at backend/evals/sets.py:300

            os.path.isdir(os.path.join(set_dir, "inputs"))
            or os.path.isfile(os.path.join(set_dir, "briefs.json"))
        ):
            continue
        infos.append(get_set(entry))
    return infos


def resolve_set_image_path(set_name: str, filename: str) -> str:
    """Absolute path of a set image; raises on traversal or missing file."""
    inputs_dir = get_set_inputs_dir(set_name)
    if not os.path.isdir(inputs_dir):
        raise EvalSetNotFoundError(f"Eval set not found: {set_name}")
    safe_name = os.path.basename(filename)
    if not safe_name.lower().endswith(".png"):
        raise InvalidSetNameError(f"Not a set image: {filename!r}")
    path = os.path.realpath(os.path.join(inputs_dir, safe_name))
    if not path.startswith(os.path.realpath(inputs_dir) + os.sep):
        raise InvalidSetNameError(f"Invalid image path: {filename!r}")
    if not os.path.isfile(path):
        raise FileNotFoundError(path)
    return path

View on GitHub (pinned to d026163f58)

Solutions

  1. Replace symlinks in inputs/ with real file copies (cp -L).
  2. If shared images are needed, copy them into the set directory.
  3. Caller-side, reject any filename containing '/' or '..' before calling resolve.

Example fix

# before
ln -s ~/shared/shot.png sets/my-set/inputs/shot.png

# after
cp ~/shared/shot.png sets/my-set/inputs/shot.png
Defensive patterns

Strategy: validation

Validate before calling

import os

def is_safe_image_filename(filename: str) -> bool:
    base = os.path.basename(filename)
    return (
        base == filename
        and "/" not in filename
        and "\\" not in filename
        and ".." not in filename
        and base.lower().endswith(".png")
    )

Try / catch

try:
    path = resolve_set_image_path(set_name, filename)
except InvalidSetNameError as e:
    abort(400, description=str(e))  # traversal or non-png: client error, not 500

Prevention

When it happens

Trigger: A symlink inside sets/{name}/inputs/ pointing to a file outside the set directory (realpath resolves through it); on platforms where the inputs dir itself is a symlink and path prefix logic mismatches; virtually unreachable for plain string traversal like "../../etc/passwd" because basename() neutralizes it first.

Common situations: Users symlinking shared image folders into a set's inputs dir instead of copying files; odd mounts or bind mounts making realpath prefixes inconsistent.

Related errors


AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14). Data as JSON: /api/errors/fa33fba15315707f. Report an issue: GitHub.