lima-vm/lima · error

symlink target %#q in %#q escapes the repository

Error message

symlink target %#q in %#q escapes the repository

What it means

symlinkTarget resolves a file-symlink target relative to the directory of the fetched file and refuses targets whose cleaned path climbs above the repository root (paths starting with ../ after path.Join/Clean). This security check prevents a template's symlink file from redirecting the fetch to a different repository or host path via .. segments.

Source

Thrown at pkg/limatmpl/github.go:200

	// A symlink must be a single line (without trailing newline), no spaces, no colons
	if !(content == "" || strings.ContainsAny(content, "\n :")) {
		// symlink is relative to the directory of filePath, and must stay within the repo
		filePath, err = symlinkTarget(filePath, content)
		if err != nil {
			return "", err
		}
	}
	return githubUserContentURL(org, repo, branch, filePath), nil
}

// symlinkTarget resolves a symlink target relative to the directory of filePath.
// It returns an error if the target escapes the repository root, so a symlink
// cannot redirect the fetch to a different repository via `../` segments.
func symlinkTarget(filePath, target string) (string, error) {
	resolved := path.Join(path.Dir(filePath), target)
	if escapesRepo(resolved) {
		return "", fmt.Errorf("symlink target %#q in %#q escapes the repository", target, filePath)
	}
	return resolved, nil
}

// escapesRepo reports whether the cleaned path climbs above the repository root.
func escapesRepo(p string) bool {
	p = path.Clean(p)
	return p == ".." || strings.HasPrefix(p, "../")
}

// resolveGitHubRedirect checks if a file at the given path is a github: URL to another file within the same repo.
// Returns the URL, or an error if the file doesn't exist, or doesn't start with github:ORG.
func resolveGitHubRedirect(ctx context.Context, org, repo, defaultBranch, filePath, origBranch string) (string, error) {
	// Refetch the filepath from the defaultBranch
	resp, err := getGitHubUserContent(ctx, org, repo, defaultBranch, filePath)
	if err != nil {
		return "", fmt.Errorf("failed to fetch file: %w", err)
	}

View on GitHub (pinned to dd909d0973)

Solutions

  1. Fix the upstream symlink file to use an in-repo relative target (no leading ../ beyond the repo root)
  2. If the file was never intended to be a symlink, reformat it so it contains a newline, space, or colon (e.g. make it a comment-bearing YAML) so it is not treated as a symlink path
  3. Reference the actual target file directly in your github: URL instead of going through the symlink
  4. Fork the template repo and correct the symlink target

Example fix

// symlink file content, before
../../../etc/passwd
// after
configs/default.yaml
Defensive patterns

Strategy: validation

Validate before calling

func safeTarget(dir, target string) bool {
    resolved := path.Clean(path.Join(dir, target))
    return resolved != ".." && !strings.HasPrefix(resolved, "../")
}
// check before fetching a template whose symlink content you control
if !safeTarget("templates", contents) {
    return errors.New("symlink target escapes repo")
}

Type guard

func escapesRepo(p string) bool {
    p = path.Clean(p)
    return p == ".." || strings.HasPrefix(p, "../")
}

Try / catch

url, err := transformGitHubURL(ctx, ref)
if err != nil && strings.Contains(err.Error(), "escapes the repository") {
    return fmt.Errorf("refusing template: symlink in %s points outside its repo; reference the target file directly", ref)
}

Prevention

When it happens

Trigger: transformGitHubURL -> resolveGitHubSymlink finds the fetched .yaml content is a single-line path (no newline, space, or colon) and calls symlinkTarget; the target resolves to a path like ../../other/repo/file.yaml that escapesRepo() flags.

Common situations: A template repo containing a symlink file that points outside its own tree (e.g. ../shared/config.yaml); content-antisymmetry mistakes where a one-line value happens to look like a path; a compromised or misconfigured upstream template attempting path traversal.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/7ed122a506124ba1. Report an issue: GitHub.