Skip to content

Commit 3eb2269

Browse files
committed
Prevent path traversal attack in FilesystemExporter
Fix validation so that relative paths cannot escape their base path by introducing "../" segments.
1 parent 8274f72 commit 3eb2269

4 files changed

Lines changed: 21 additions & 1 deletion

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved validation of relative paths to prevent a path traversal attack in filesystem exports. (CVE-2026-12701)

pulpcore/app/serializers/fields.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ def relative_path_validator(relative_path):
2020
raise serializers.ValidationError(
2121
_("Relative path can't start with '/'. {0}").format(relative_path)
2222
)
23+
if os.path.normpath(relative_path).startswith("../"):
24+
raise serializers.ValidationError(
25+
_("Relative path must not reach beyond the base path. {0}").format(relative_path)
26+
)
2327

2428

2529
# Prefer JSONDictField and JSONListField over JSONField:

pulpcore/app/tasks/export.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
Task,
3030
)
3131
from pulpcore.app.models.content import ContentArtifact
32-
from pulpcore.app.serializers import PulpExportSerializer
32+
from pulpcore.app.serializers import PulpExportSerializer, relative_path_validator
3333
from pulpcore.app.util import Crc32Hasher, compute_file_hash
3434
from pulpcore.constants import FS_EXPORT_METHODS
3535

@@ -98,6 +98,7 @@ def _export_to_file_system(path, relative_paths_to_artifacts, method=FS_EXPORT_M
9898
method = FS_EXPORT_METHODS.WRITE
9999

100100
for relative_path, artifact in relative_paths_to_artifacts.items():
101+
relative_path_validator(relative_path)
101102
dest = os.path.join(path, relative_path)
102103
os.makedirs(os.path.split(dest)[0], exist_ok=True)
103104

pulpcore/tests/unit/serializers/test_fields.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from rest_framework import serializers
33

44
from pulpcore.app.serializers import fields
5+
from pulpcore.app.serializers.fields import relative_path_validator
56

67

78
@pytest.mark.parametrize(
@@ -47,3 +48,16 @@ def test_custom_json_dict_field_raises(field_and_data, binary_arg):
4748
error_msg = "Invalid type"
4849
with pytest.raises(serializers.ValidationError, match=error_msg):
4950
custom_field.to_internal_value(data)
51+
52+
53+
@pytest.mark.parametrize(
54+
("path",),
55+
[
56+
pytest.param("/absolute/path", id="absolute"),
57+
pytest.param("../sneaky/path", id="path_traversal"),
58+
pytest.param("suspicious/../../sneaky/path", id="hidden_path_traversal"),
59+
],
60+
)
61+
def test_relative_path_validator_rejects(path):
62+
with pytest.raises(serializers.ValidationError):
63+
relative_path_validator(path)

0 commit comments

Comments
 (0)