From a98bb4d8667b96f8ea67fe1d1a50ae9ccde2ff0f Mon Sep 17 00:00:00 2001 From: ChuckBuilds Date: Mon, 7 Sep 2026 15:44:51 -0400 Subject: [PATCH] fix(starlark): stop three more error paths leaking exception text CodeQL's three remaining stack-trace-exposure alerts were real, not noise like the path ones -- these answered the caller with the exception: 'Failed to save configuration: {e}' 'File error during upload: {err}' 'Failed to load app module: {err}' An OSError there names absolute paths on the device. All three already logged the detail; the response now says what failed and nothing more, matching the generic Exception arm sitting directly beneath two of them. That leaves 25 CodeQL alerts on this PR, all of a kind: 24 path-injection where traversal is demonstrably blocked, and one command-line-injection on a list-form subprocess with no shell. Both classes already appear on main -- api_v3.py carries 11 path-injection and 69 stack-trace alerts before this change. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9 --- web_interface/blueprints/api_v3.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web_interface/blueprints/api_v3.py b/web_interface/blueprints/api_v3.py index 15720ac3..06340a0c 100644 --- a/web_interface/blueprints/api_v3.py +++ b/web_interface/blueprints/api_v3.py @@ -9289,11 +9289,14 @@ def upload_starlark_app(): pass except (OSError, IOError) as err: + # The detail goes to the log, not the response: it names absolute + # paths on the device, which the caller has no business seeing. The + # generic Exception arm below already did this; these two did not. logger.exception("[Starlark] File error uploading starlark app: %s", err) - return jsonify({'status': 'error', 'message': f'File error during upload: {err}'}), 500 + return jsonify({'status': 'error', 'message': 'File error during upload'}), 500 except ImportError as err: logger.exception("[Starlark] Module load error uploading starlark app: %s", err) - return jsonify({'status': 'error', 'message': f'Failed to load app module: {err}'}), 500 + return jsonify({'status': 'error', 'message': 'Failed to load app module'}), 500 except Exception as err: logger.exception("[Starlark] Unexpected error uploading starlark app: %s", err) return jsonify({'status': 'error', 'message': 'Failed to upload app'}), 500 @@ -9479,7 +9482,8 @@ def update_starlark_app_config(app_id): json.dump(current_config, f, indent=2) except Exception as e: logger.error(f"Failed to save config.json for {app_id}: {e}") - return jsonify({'status': 'error', 'message': f'Failed to save configuration: {e}'}), 500 + logger.exception("Failed to save Starlark configuration for %r", app_id) + return jsonify({'status': 'error', 'message': 'Failed to save configuration'}), 500 # Also update manifest for backward compatibility app_data.setdefault('config', {}).update(data)