Skip to content

Throw when copying from paths outside the context dir#1067

Draft
mishushakov wants to merge 30 commits intomainfrom
fix-throw-on-copy-abs-rel-paths
Draft

Throw when copying from paths outside the context dir#1067
mishushakov wants to merge 30 commits intomainfrom
fix-throw-on-copy-abs-rel-paths

Conversation

@mishushakov
Copy link
Member

@mishushakov mishushakov commented Jan 8, 2026

Note

Medium Risk
Introduces stricter validation and path normalization for copy inputs, which can break existing templates that relied on absolute paths or .. traversal; otherwise changes are localized and well-covered by tests.

Overview
Prevents path traversal in template copy operations by throwing when the source path is outside the template context directory (absolute paths, .. escapes), while preserving stack traces for better error attribution.

Adds cross-platform path normalization (normalizePath/normalize_path) and a shared safety check (isSafeRelative/is_safe_relative) in both the JS and Python SDKs, and updates CLI fixtures and Dockerfile parsing/tests to reflect normalized destinations (e.g., removing trailing slashes) plus new unit coverage for the helpers.

Written by Cursor Bugbot for commit bd60304. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link

changeset-bot bot commented Jan 8, 2026

🦋 Changeset detected

Latest commit: bd60304

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@e2b/python-sdk Patch
e2b Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da296034db

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@mishushakov mishushakov enabled auto-merge (squash) January 8, 2026 14:18
Copy link
Member

@jakubno jakubno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't we throw directly in .copy() command? Can't you resolve the path directly there? You want to work with the relative path ideally everywhere anyway?

@mishushakov
Copy link
Member Author

Cursor review

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no bugs!


for (const src of srcs) {
const normalizedSrc = normalizePath(src.toString())
const normalizedDest = normalizePath(dest.toString())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move this outside of the for loop

expect(isSafeRelative('../file.txt')).toBe(false)
})

test('should return true for paths starting with ..\\', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test('should return true for paths starting with ..\\', () => {
test('should return false for paths starting with ..\\', () => {

expect(isSafeRelative('..\\file.txt')).toBe(false)
})

test('should return true for normalized paths that escape context', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test('should return true for normalized paths that escape context', () => {
test('should return false for normalized paths that escape context', () => {

expect(isSafeRelative('..')).toBe(false)
})

test('should return true for paths starting with ../', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test('should return true for paths starting with ../', () => {
test('should return false for paths starting with ../', () => {

expect(isSafeRelative('./folder/file.txt')).toBe(true)
})

test('should return false for glob patterns', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test('should return false for glob patterns', () => {
test('should return true for glob patterns', () => {

Comment on lines +51 to +55
# Determine if absolute
is_absolute = working_path.startswith("/") or working_path.startswith("\\")

# Normalize separators to '/'
normalized_path = re.sub(r"[\\/]+", "/", working_path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverse the order to simplify


for part in parts:
if part == "..":
if normalized and normalized[-1] != "..":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue as in JS with ./..

os.path.isabs(norm_path)
or norm_path == ".."
or norm_path.startswith("../")
or norm_path.startswith("..\\")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normpath doesn't contain \ anymore right?

dockerfile = """FROM node:24
COPY --chown=myuser:mygroup app.js /app/
COPY --chown=anotheruser config.json /config/"""
COPY --chown=myuser:mygroup app.js /app
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove the extra slashes?

from e2b.template.utils import normalize_path


class TestBasicPathNormalization:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a test with ./..

@mishushakov mishushakov marked this pull request as draft January 29, 2026 16:07
auto-merge was automatically disabled January 29, 2026 16:07

Pull request was converted to draft

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants