Skip to content

ForbiddenPathError raised for legitimate external symlinks during update #2333

@davidpoblador

Description

@davidpoblador

Summary

I encountered an issue where copier update fails with ForbiddenPathError when the destination directory contains symlinks pointing outside the project directory, even though these symlinks represent legitimate use cases.

Steps to Reproduce

  1. Create a project using copier
  2. Create a symlink in the destination that points outside the project directory:
    ln -s /external/path/.env.local .env.local
  3. Run copier update on the project
  4. Observe ForbiddenPathError: ".env.local" is forbidden

Expected Behavior

The update should succeed, as the symlink itself is within the project directory and represents a legitimate configuration pattern (e.g., environment files stored securely outside the project).

Actual Behavior

copier.errors.ForbiddenPathError: ".env.local" is forbidden

Root Cause Analysis

The issue appears to be in _main.py around line 725, where the security check resolves symlinks before validating paths:

if not cwd.joinpath(dst_relpath).resolve().is_relative_to(cwd):
    raise ForbiddenPathError(path=dst_relpath)

When a symlink points outside the project, .resolve() returns the external path, which triggers the forbidden path check even though the symlink itself is legitimately within the project.

Use Case Context

This pattern is common for:

  • Environment files (.env.local → external secrets directory)
  • Configuration files stored outside version control
  • Shared resources between projects

The current behavior prevents these legitimate patterns while the security intent (preventing path traversal attacks) could be preserved by checking symlink paths differently.

Environment

  • copier version: [latest]
  • Python version: 3.13
  • OS: macOS (though likely affects all platforms)

Proposed Solution

I have prepared a potential fix that addresses this issue while maintaining existing security protections. The fix distinguishes between existing symlinks and regular files during path validation.

I'd be happy to contribute this fix if it seems like a valid issue to address. Thank you for maintaining this excellent tool!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions