From 9d58567d081459b0edb9925f8d30cc072faf9125 Mon Sep 17 00:00:00 2001 From: Nayana Naik Date: Sun, 25 Oct 2026 16:41:13 +0530 Subject: [PATCH] Reject partition values that are not a single path segment --- cpp/src/arrow/dataset/partition.cc | 7 +++++++ cpp/src/arrow/dataset/partition_test.cc | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/cpp/src/arrow/dataset/partition.cc b/cpp/src/arrow/dataset/partition.cc index 4d5c6e8ce7a7..7332e6eb4972 100644 --- a/cpp/src/arrow/dataset/partition.cc +++ b/cpp/src/arrow/dataset/partition.cc @@ -322,6 +322,13 @@ Result> KeyValuePartitioning::FormatPartitionSegments( for (int i = 0; i < schema_->num_fields(); ++i) { if (values[i] != nullptr && values[i]->is_valid) { segments[i] = values[i]->ToString(); + // The value is used verbatim as a path segment, so it must not be able + // to escape or add a directory level + if (segments[i] == "." || segments[i] == ".." || + segments[i].find(fs::internal::kSep) != std::string::npos) { + return Status::Invalid("Partition value for ", schema_->field(i)->name(), + " cannot be used as a path segment: ", segments[i]); + } continue; } diff --git a/cpp/src/arrow/dataset/partition_test.cc b/cpp/src/arrow/dataset/partition_test.cc index 9f0bd7c0be04..0205117e3b61 100644 --- a/cpp/src/arrow/dataset/partition_test.cc +++ b/cpp/src/arrow/dataset/partition_test.cc @@ -310,6 +310,22 @@ TEST_F(TestPartitioning, DirectoryPartitioningFormat) { equal(field_ref("beta"), literal("hello")))); } +TEST_F(TestPartitioning, DirectoryPartitioningFormatInvalidSegment) { + partitioning_ = + std::make_shared(schema({field("alpha", utf8())})); + written_schema_ = partitioning_->schema(); + + AssertFormat(equal(field_ref("alpha"), literal("..a")), "..a"); + AssertFormatError(equal(field_ref("alpha"), literal(".."))); + AssertFormatError(equal(field_ref("alpha"), literal("."))); + AssertFormatError(equal(field_ref("alpha"), literal("../../escaped"))); + AssertFormatError(equal(field_ref("alpha"), literal("a/b"))); + + partitioning_ = + std::make_shared(schema({field("alpha", utf8())})); + AssertFormatError(equal(field_ref("alpha"), literal("../../escaped"))); +} + TEST_F(TestPartitioning, DirectoryPartitioningFormatDictionary) { auto dictionary = ArrayFromJSON(utf8(), R"(["hello", "world"])"); partitioning_ = std::make_shared(schema({DictStr("alpha")}),