Consolidating code ql findings (#2920)

* Consolidating code ql findings

* Added ref files for backstop to set baseline for removing custom js file

* Potential fix for code scanning alert no. 32: URL redirection from remote source

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Removed unused large file

* Fixed import order

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
Alex Janousek
2025-09-18 16:42:39 -04:00
committed by GitHub
parent 34d6c827c2
commit 8057c7f8dc
42 changed files with 60 additions and 7100 deletions

View File

@@ -90,7 +90,12 @@ def organization_dashboard(org_id):
@main.route("/organizations/<uuid:org_id>/download-usage-report.csv", methods=["GET"])
@user_has_permissions()
def download_organization_usage_report(org_id):
selected_year = request.args.get("selected_year")
selected_year_input = request.args.get("selected_year")
# Validate selected_year to prevent header injection
if selected_year_input and selected_year_input.isdigit() and len(selected_year_input) == 4:
selected_year = selected_year_input
else:
selected_year = str(datetime.now().year)
services_usage = current_organization.services_and_usage(
financial_year=selected_year
)["services"]
@@ -121,6 +126,11 @@ def download_organization_usage_report(org_id):
for service in services_usage
]
# Sanitize organization name for filename to prevent header injection
import re
safe_org_name = re.sub(r'[^\w\s-]', '', current_organization.name).strip()
safe_org_name = re.sub(r'[-\s]+', '-', safe_org_name)
return (
Spreadsheet.from_rows(org_usage_data).as_csv_data,
200,
@@ -130,7 +140,7 @@ def download_organization_usage_report(org_id):
"inline;"
'filename="{} organization usage report for year {}'
' - generated on {}.csv"'.format(
current_organization.name,
safe_org_name,
selected_year,
datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
)

View File

@@ -1,4 +1,5 @@
from functools import partial
from urllib.parse import urlparse
from flask import abort, flash, jsonify, redirect, render_template, request, url_for
from flask_login import current_user
@@ -194,7 +195,19 @@ def process_folder_management_form(form, current_folder_id):
ids_to_move=form.templates_and_folders.data, move_to=move_to_id
)
return redirect(request.url)
# Use request.full_path which includes query string but not host
# This avoids host header injection while preserving all parameters
# Hardened redirect: only allow relative URLs, and strip any backslashes
target = request.full_path.replace('\\', '')
parts = urlparse(target)
if not parts.scheme and not parts.netloc and target.startswith('/'):
return redirect(target)
# Fallback to main template list for this service
return redirect(url_for(
'.choose_template',
service_id=current_service.id,
template_type='all'
))
def get_template_nav_label(value):