From 3ce2a5bc26a9b1eb34f20dac354e6d76390fd6cb Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 6 Apr 2026 15:12:44 -0400 Subject: [PATCH] More tightly constrain node profile requests Normalize paths using abspath and validate the result is within the expected path. --- confluent_server/confluent/selfservice.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/selfservice.py b/confluent_server/confluent/selfservice.py index 44aa5619..872463ec 100644 --- a/confluent_server/confluent/selfservice.py +++ b/confluent_server/confluent/selfservice.py @@ -578,8 +578,13 @@ def handle_request(env, start_response): yield 'No profile' return fname = '/var/lib/confluent/private/os/{}/{}'.format(profile, fname) + fullpath = os.path.abspath(fname) + if not fullpath.startswith('/var/lib/confluent/private/os/{}/'.format(profile)): + start_response('400 Bad Request', ()) + yield 'Bad Request' + return try: - with open(fname, 'rb') as privdata: + with open(fullpath, 'rb') as privdata: start_response('200 OK', ()) yield privdata.read() return @@ -623,6 +628,11 @@ def get_scriptlist(scriptcat, cfg, nodename, pathtemplate): 'deployment.profile', {}).get('value', '') slist = [] target = pathtemplate.format(profile, scriptcat) + target = os.path.abspath(target) + allowedbase = os.path.abspath(pathtemplate.format(profile, '').rstrip('/')) + allowedbaseprefix = os.path.join(allowedbase, '') + if not target.startswith(allowedbaseprefix): + return None, None if not os.path.isdir(target) and os.path.isdir(target + '.d'): target = target + '.d' try: