mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-18 05:29:38 -04:00
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:
@@ -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"),
|
||||
)
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user