Skip to content

Commit 42688e4

Browse files
SckyzOclaude
andcommitted
security: fix path traversal vulnerability in metadata scripts
Add input validation to prevent path traversal attacks (CWE-22) in: - aggregate_catalog_metadata.py - generate_artifact_metadata.py Changes: - Add validate_exporter_name() function with regex validation - Reject exporter names containing '..' or path separators - Use Path.resolve() for absolute path resolution - Add relative_to() safety check to prevent directory escape Fixes CodeQL high severity security alert in PR #46. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent afb2f50 commit 42688e4

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

core/scripts/aggregate_catalog_metadata.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ def aggregate_metadata(
212212
}
213213

214214

215+
def validate_exporter_name(name: str) -> bool:
216+
"""
217+
Validate exporter name to prevent path traversal attacks.
218+
219+
Returns True if the name is safe, False otherwise.
220+
"""
221+
# Exporter names should only contain alphanumeric, underscore, hyphen
222+
import re
223+
if not re.match(r'^[a-zA-Z0-9_-]+$', name):
224+
return False
225+
226+
# Explicitly reject path traversal patterns
227+
if '..' in name or '/' in name or '\\' in name:
228+
return False
229+
230+
return True
231+
232+
215233
def main():
216234
parser = argparse.ArgumentParser(
217235
description="Aggregate artifact metadata into exporter metadata.json"
@@ -231,10 +249,30 @@ def main():
231249

232250
args = parser.parse_args()
233251

252+
# Validate exporter name to prevent path traversal
253+
if not validate_exporter_name(args.exporter):
254+
print(
255+
f"Error: Invalid exporter name '{args.exporter}'. "
256+
"Exporter names must contain only alphanumeric characters, underscores, and hyphens.",
257+
file=sys.stderr,
258+
)
259+
sys.exit(1)
260+
234261
# Paths
235-
catalog_dir = Path(args.catalog_dir)
262+
catalog_dir = Path(args.catalog_dir).resolve() # Resolve to absolute path
236263
exporter_dir = catalog_dir / args.exporter
237-
manifest_path = Path(args.manifest_path)
264+
manifest_path = Path(args.manifest_path).resolve() # Resolve to absolute path
265+
266+
# Additional safety check: ensure exporter_dir is within catalog_dir
267+
try:
268+
exporter_dir.resolve().relative_to(catalog_dir)
269+
except ValueError:
270+
print(
271+
"Error: Exporter directory escapes catalog directory. "
272+
"This is not allowed for security reasons.",
273+
file=sys.stderr,
274+
)
275+
sys.exit(1)
238276

239277
# Load manifest
240278
manifest = load_manifest(manifest_path)

core/scripts/generate_artifact_metadata.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,24 @@ def generate_docker_metadata(args: argparse.Namespace) -> Dict[str, Any]:
198198
}
199199

200200

201+
def validate_exporter_name(name: str) -> bool:
202+
"""
203+
Validate exporter name to prevent path traversal attacks.
204+
205+
Returns True if the name is safe, False otherwise.
206+
"""
207+
# Exporter names should only contain alphanumeric, underscore, hyphen
208+
import re
209+
if not re.match(r'^[a-zA-Z0-9_-]+$', name):
210+
return False
211+
212+
# Explicitly reject path traversal patterns
213+
if '..' in name or '/' in name or '\\' in name:
214+
return False
215+
216+
return True
217+
218+
201219
def main():
202220
parser = argparse.ArgumentParser(
203221
description="Generate artifact metadata JSON for catalog"
@@ -254,6 +272,15 @@ def main():
254272

255273
args = parser.parse_args()
256274

275+
# Validate exporter name to prevent path traversal
276+
if not validate_exporter_name(args.exporter):
277+
print(
278+
f"Error: Invalid exporter name '{args.exporter}'. "
279+
"Exporter names must contain only alphanumeric characters, underscores, and hyphens.",
280+
file=sys.stderr,
281+
)
282+
sys.exit(1)
283+
257284
# Validate required fields per type
258285
if args.type in ["rpm", "deb"]:
259286
required = ["arch", "dist", "filename", "url", "sha256", "size"]

0 commit comments

Comments
 (0)