@@ -46,10 +46,10 @@ public class SnapshotOptions
4646 public static final String SKIP_FLUSH = "skipFlush" ;
4747 public static final String TTL = "ttl" ;
4848
49- // Conservative subset of the AWS S3 "Safe characters" set: 0-9 a-z A-Z - _ .
50- // See the validation site in validateTag for the full rationale on excluded characters .
49+ // Allowed snapshot-name characters: 0-9 a-z A-Z - _ . +
50+ // See the validation site in validateTag for the full rationale (an S3 safe-set subset, plus '+') .
5151 // Hyphen is placed last in the character class, so it stays literal and never becomes a range operator.
52- private static final Pattern SAFE_SNAPSHOT_NAME = Pattern .compile ("[a-zA-Z0-9_.-]+" );
52+ private static final Pattern SAFE_SNAPSHOT_NAME = Pattern .compile ("[a-zA-Z0-9_.+ -]+" );
5353
5454 public final SnapshotType type ;
5555 public final String tag ;
@@ -247,10 +247,12 @@ private void validateTag(String tag)
247247 // Allowed characters are a conservative subset of the AWS S3 "Safe characters" set
248248 // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-guidelines):
249249 // 0-9 a-z A-Z - _ .
250+ // plus '+', which is not an S3 "Safe character" but can legitimately appear in system
251+ // snapshot names via version build metadata (e.g. an upgrade snapshot "<millis>-upgrade-5.0.4+build-...").
250252 // The remaining S3-safe characters (! * ' ( )) are intentionally excluded as they are
251253 // shell-significant and error-prone in paths, and the path separator '/' is excluded too,
252254 // which is what blocks traversal attempts such as "../../mysnapshot"
253- if (type == SnapshotType . USER && !SAFE_SNAPSHOT_NAME .matcher (resolvedSnapshotName ).matches ())
255+ if (!SAFE_SNAPSHOT_NAME .matcher (resolvedSnapshotName ).matches ())
254256 {
255257 throw new IllegalArgumentException ("Snapshot name contains illegal characters: " + resolvedSnapshotName + ". " +
256258 "Allowed characters must match the pattern: " + SAFE_SNAPSHOT_NAME .pattern () +
0 commit comments