{"record":{"id":"92b2cef763fdf565","repo":"apache/cassandra","slug":"snapshot-name-cannot-contain","errorCode":null,"errorMessage":"Snapshot name cannot contain ","messagePattern":"Snapshot name cannot contain ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java","lineNumber":220,"sourceCode":"        public SnapshotOptions build()\n        {\n            validateTag(tag);\n            validateTTL(ephemeral, ttl);\n\n            if (rateLimiter == null)\n                rateLimiter = DatabaseDescriptor.getSnapshotRateLimiter();\n\n            return new SnapshotOptions(this);\n        }\n\n        private void validateTag(String tag)\n        {\n            if (tag == null || tag.isEmpty())\n                throw new IllegalArgumentException(\"You must supply a snapshot name.\");\n\n            if (tag.contains(File.pathSeparator()))\n            {\n                throw new IllegalArgumentException(\"Snapshot name cannot contain \" + File.pathSeparator());\n            }\n\n            if (tag.equals(\".\") || tag.equals(\"..\"))\n            {\n                throw new IllegalArgumentException(\"Snapshot name '\" + tag + \"' is reserved\");\n            }\n\n            if (!CassandraRelevantProperties.SNAPSHOT_NAME_VALIDATION.getBoolean())\n                return;\n\n            // Pre-generate snapshot name for the sake of the validation.\n            // getSnapshotName logic does not return raw \"tag\" as snapshot name every time,\n            // it e.g. prepends timestamp and type for system snapshots, and we need to validate it as a whole.\n            // If, for example, tag would be less than max allowed FILENAME_LENGTH,\n            // we might in fact produce a snapshot name longer than FILENAME_LENGTH if we prepended a timestamp to it.\n            String resolvedSnapshotName = SnapshotOptions.getSnapshotName(type, tag, now());\n\n            // the length of valid snapshot name has to be less than or equal to FILENAME_LEGTH - that is 255 -","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java#L202-L238","documentation":"validateTag rejects snapshot names containing the platform path separator, because the tag becomes a filesystem directory name and a separator would create unexpected nested paths (path traversal risk).","triggerScenarios":"Passing a tag containing '/' (or '\\' on Windows), e.g. building hierarchical names like 'daily/ks1' or accepting user-controlled tags with slashes.","commonSituations":"Scripts composing tags from paths or URLs; multi-tenant input sanitization gaps; Windows/Linux tag reuse across environments.","solutions":["Replace separators in the tag with a safe character, e.g. tag.replace('/', '_').","Pre-validate the tag with a whitelist regex like [A-Za-z0-9._-]+ before calling the API.","Sanitize user-supplied snapshot names server-side before passing them to snapshot creation.","Use SnapshotOptions' validation (SNAPSHOT_NAME_VALIDATION property) in tests to catch bad tags early."],"exampleFix":"// before\nString tag = \"daily/\" + keyspace;\ntakeSnapshot(tag, keyspace);\n// after\nString tag = (\"daily/\" + keyspace).replace('/', '_');\ntakeSnapshot(tag, keyspace);","handlingStrategy":"validation","validationCode":"boolean isSafeTag(String tag) { return tag != null && tag.matches(\"[A-Za-z0-9._-]+\") && !tag.equals(\".\") && !tag.equals(\"..\"); }","typeGuard":null,"tryCatchPattern":"try { takeSnapshot(tag, ks); } catch (IllegalArgumentException e) { log.error(\"Invalid snapshot tag '{}': {}\", tag, e.getMessage()); }","preventionTips":["Sanitize user-supplied tags against a whitelist","Replace path separators with '_'","Enable SNAPSHOT_NAME_VALIDATION in staging to catch bad tags"],"tags":["snapshot","validation","path-traversal","illegalargument"],"backgroundTag":"path-traversal-blocked","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}