Directory traversal issue when organizing a part
Metadata
Current evaluation
Fixed by merged PR #1562 (commit 32b95b4f), rejecting organize sources that escape the install directory via absolute paths or traversal.
Resolution: closed resolved
Reason: PR #1562 was merged as commit 32b95b4f and added validation that organize sources remain within the part install directory. The maintainer explicitly closed #1525 via that PR.
Evaluated by: mr-cal-bot
No scores available.
Issue body
### Bug Description
When organizing a part, it's possible to organize from any directory, not just subdirectories of the install directory.
### To Reproduce
Run `python -m craft_parts` on the parts.yaml file below. Note how the contents of `/etc/apt` get placed into the prime directory.
It's also possible to use directory traversal strings to get a relative directory.
### part yaml
```shell
parts:
a:
plugin: nil
organize:
/etc/apt: ''
```
### Relevant log output
```shell
DEBUG:craft_parts.packages:get repository attribute: attr=configure, repository:<class 'craft_parts.packages.deb.Ubuntu'>
DEBUG:craft_parts.utils.os_utils:is_snap: False, SNAP_NAME set to None
DEBUG:craft_parts.sequencer:process a:1
DEBUG:craft_parts.sequencer:add action a:1(0)
DEBUG:craft_parts.sequencer:process a:2
DEBUG:craft_parts.sequencer:add action a:2(0)
DEBUG:craft_parts.sequencer:process a:3
DEBUG:craft_parts.sequencer:add action a:3(0)
DEBUG:craft_parts.sequencer:process a:4
DEBUG:craft_parts.sequencer:add action a:4(0)
DEBUG:craft_parts.sequencer:process a:5
DEBUG:craft_parts.sequencer:add action a:5(0)
INFO:craft_parts.executor.executor:Installing build-packages
DEBUG:craft_parts.packages:get repository attribute: attr=install_packages, repository:<class 'craft_parts.packages.deb.Ubuntu'>
DEBUG:craft_parts.executor.executor:verify plugin environment for part 'a'
DEBUG:craft_parts.packages:set repository attribute: attr=stage_packages_filters, value=None, repo:<class 'craft_parts.packages.deb.Ubuntu'>
Execute: Pull a
DEBUG:craft_parts.executor.executor:execute action a:Action(part_name='a', step=Step.PULL, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None))
Execute: Overlay a
DEBUG:craft_parts.executor.executor:execute action a:Action(part_name='a', step=Step.OVERLAY, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None))
Execute: Build a
DEBUG:craft_parts.executor.executor:execute action a:Action(part_name='a', step=Step.BUILD, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None))
DEBUG:craft_parts.state_manager.states:load state file: /home/lengau/Work/Code/craft-parts/parts/a/state/pull
DEBUG:craft_parts.packages:get repository attribute: attr=unpack_stage_packages, repository:<class 'craft_parts.packages.deb.Ubuntu'>
DEBUG:craft_parts.executor.part_handler:remove directory /home/lengau/Work/Code/craft-parts/parts/a/build
DEBUG:craft_parts.executor.step_handler:Executing PosixPath('/home/lengau/Work/Code/craft-parts/parts/a/run/build.sh')
DEBUG:craft_parts.executor.part_handler:Run pre-organize callbacks
DEBUG:craft_parts.packages:get repository attribute: attr=get_installed_packages, repository:<class 'craft_parts.packages.deb.Ubuntu'>
DEBUG:urllib3.connectionpool:http://localhost:None "GET /v2/snaps HTTP/1.1" 200 None
Execute: Stage a
DEBUG:craft_parts.executor.executor:execute action a:Action(part_name='a', step=Step.STAGE, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None))
Execute: Prime a
DEBUG:craft_parts.executor.executor:execute action a:Action(part_name='a', step=Step.PRIME, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None))
```
Evaluation history
| Date | Model | Scores | Action | Summary |
|---|---|---|---|---|
| stealth/space-bunny-alpha | — | closed resolved | Fixed by merged PR #1562 (commit 32b95b4f), rejecting organize sources that escape the install directory via absolute paths or traversal. | |
| stealth/space-bunny-alpha | — | closed resolved | Fixed directory traversal in organize by rejecting sources outside the part install directory in merged PR #1562, commit 32b95b4f. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed via PR #1562. Added validation to reject organize source paths escaping the part install directory, blocking directory traversal and absolute path misuse. Merged and closed. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed and merged via PR #1562. The update rejects organize source paths that escape the part install directory, including absolute paths and directory traversal strings. This resolves the bug by validating paths before processing. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed via PR #1562. The organize step now rejects source paths escaping the part install directory, preventing directory traversal and absolute path vulnerabilities. Merged as a bugfix. |
Update history
No update history recorded yet.
Related work
-
Likely Fixed By:
canonical/craft-parts#1562
(confidence 100%)
Merged fix for absolute-path and directory-traversal handling in organize entries.
Related issues
| Issue | Project | State | Summary | Similarity |
|---|---|---|---|---|
| #1562 fix(organize): reject sources outside install dir | craft-parts | merged | Merged PR #1562 as commit 32b95b4f, rejecting organize sources outside the install directory while preserving existing symlink behavior. | |
| #690 fix(organize): use the part's install directories (#689) | craft-parts | merged | Merged PR #690 in commit 0eff7cc9 (change c349e740), fixing organize_files() to use part install directories and organize under base_dir. | |
| #1544 fix: prevent organizing a directory into itself | craft-parts | closed | PR #1544 was closed unmerged as incomplete; the solution was replaced by the organize-from-build rework in #1598 (commit cc02958b). | |
| #689 fix(organize): use the part's install directories | craft-parts | merged | Merged craft-parts#689: organize_files now receives each part's install directories instead of recreating relative paths, ensuring organization uses base_dir rather than cwd. | |
| #673 Organizing files fails if equivalent file already exists | craft-parts | closed | Organize collisions were fixed by PR #689 (commit c349e740), making organize_files() use part install directories instead of cwd-relative paths. |