# Triage Report: FRC5892/HeroHours
REAL THREATS
Privilege Escalation & Access Control
[0] CRITICAL | Superuser can create arbitrary staff accounts
The
/add_user endpoint (admin.py:306) allows any superuser to create new staff users with arbitrary credentials and group assignments. While protected by
@user_passes_test(is_superuser), this is by-design admin functionality, not a vulnerability. *However*, combined with other authentication bypasses, this becomes exploitable if an attacker can gain superuser access.
Rating: Administrative feature, not exploitable in isolation.[6] HIGH | Horizontal privilege escalation in check-in/check-out
The
handle_entry endpoint (views.py:43) only checks for
HeroHours.change_users permission but does not verify the authenticated user is authorized to check in/out *that specific user_input*. Any user with the permission can manipulate any other user's attendance records.
Real threat: horizontal privilege escalation.Credential & Authentication Leakage
[1] CRITICAL | Credentials in URL query string with full data exposure
The
sheet_pull endpoint (views.py:228) accepts base64-encoded
username:password in the URL
key parameter, authenticates the user, then returns the entire Users table as CSV. Credentials appear in server logs, browser history, and referrer headers. Agreement: 19/62 reviewers.
Real threat: credential exposure + mass data exfiltration.[2] CRITICAL | Plaintext credentials in URL (duplicate of [1])
Same root cause as [1].
Duplicate finding.[17] HIGH | API tokens in URL query parameters
The API authentication (HeroHours_api/authentication.py:97) reads tokens from
?key= query parameter, exposing bearer tokens in logs and browser history. Agreement: 7/62.
Real threat: token exposure.[18] HIGH | API endpoints use URL token auth (duplicate of [17])
Same mechanism, same exposure.
Duplicate finding.Mass Data Exfiltration
[9] HIGH | Unrestricted serialization of all user data
The
send_data_to_google_sheet endpoint (views.py:204) serializes all Users and ActivityLog records without field filtering, sending internal state (Is_Active, Checked_In, Total_Hours, etc.) to an external Google Apps Script. Agreement: 6/62.
Real threat: over-permissive data export.[12] HIGH | sheet_pull returns all users without authorization
After authenticating via the URL credential (see [1]),
sheet_pull returns *all* user records to any valid user, no role check. Agreement: 1/62 but code is clear.
Real threat: unauthorized mass data access.[19] HIGH | SheetPullAPI returns all users without scoping
The API endpoint
/api/sheet_pull returns
Users.objects.all() to any authenticated API user. In a multi-tenant or team-scoped deployment, this leaks cross-team data. Agreement: 4/62.
Real threat if multi-tenant; needs context.Injection Vulnerabilities
[13] HIGH | CSV injection in sheet_pull
User-controlled fields (First_Name, Last_Name) are interpolated directly into CSV without escaping. If a user registers with a name like
=1+1 or
@SUM(A1:A10), Excel/Sheets will execute formulas. Agreement: 5/62.
Real threat: CSV injection leading to code execution in spreadsheet clients.[23] MEDIUM | DOM-based XSS via innerHTML
The
updateMemberRow function in live.html:82 uses template literals to construct HTML and assigns to
tr.innerHTML with data from WebSocket messages. If the WebSocket data includes user-controlled content (e.g., First_Name, Last_Name), it can inject script tags. Agreement: 2/62.
Real threat: XSS if WebSocket data includes unsanitized user input.Insecure Configuration
[5] HIGH | Debug toolbar exposed unconditionally
The debug toolbar is registered at
__debug__/ in urls.py:13 without environment checks. In production, this exposes SQL queries, settings, request/response data. Agreement: 8/62.
Real threat in production deployment.[14] [15] [16] HIGH | Debug toolbar in settings (duplicates of [5])
Same issue reported three times (settings.py inclusion).
Duplicate findings.[22] HIGH | Hardcoded database password in docker-compose.yml
The postgres password is hardcoded as
password with a comment "I swear if you use this in production...". If this file is used in production, it's a credential leak. Agreement: 4/62.
Real threat if deployed as-is.False Positives & Low-Risk Findings
[3] HIGH | add_user creates staff with client-controlled credentials (duplicate of [0])
Same endpoint, same behavior.
Duplicate.[4] HIGH | Password set after create_user
The code
user.set_password(raw_password=password) is Django's correct API for setting passwords. The method automatically hashes the password. This is not a vulnerability.
False positive.[7] HIGH | Bulk check-in when DEBUG is True
The
-404 command bulk-checks-in all users *only when DEBUG is True*. This is a debug/testing feature, not exploitable in production (where DEBUG should be False).
Low risk: debug-only feature.[8] HIGH | Negative time values in auto-checkout
The threshold subtraction logic could theoretically produce negative deltas, but the code
(time - timedelta(seconds=threshold)) - user.Last_In will still yield a positive timedelta if
time - user.Last_In > threshold. The logic is correct. Agreement: 1/62.
False positive.[10] HIGH | Full records sent to Google Sheets (duplicate of [9])
Same exfiltration mechanism.
Duplicate.[11] HIGH | Unvalidated APP_SCRIPT_URL from environment
The URL is read from an environment variable and used in
requests.post(). If an attacker can modify environment variables, the application is already fully compromised. This is not a runtime vulnerability.
False positive: requires pre-compromise.[20] HIGH | SheetPullAPI exposes PII (duplicate of [19])
Same endpoint, same issue.
Duplicate.[21] HIGH | SQL injection in MeetingPullAPI date filter
Django ORM filters like
timestamp__day=str_day accept strings and safely parameterize them. The ORM prevents SQL injection. Agreement: 3/62 claimed SQL injection, but this is incorrect.
False positive.---
ATTACK CHAINS
Chain 1: Full Account Takeover + Data Exfiltration
1. Attacker intercepts or guesses credentials from logs/browser history via [1] or [17] (credentials/tokens in URLs)
2. Uses stolen credentials to authenticate to [12] sheet_pull or [19] SheetPullAPI
3. Exfiltrates all user PII, attendance records, hours
4. Uses CSV injection [13] to deliver malicious payloads to administrators opening exported sheets
Chain 2: Insider Threat / Horizontal Privilege Escalation
1. Authenticated user with HeroHours.change_users permission accesses [6] handle_entry
2. Manipulates other users' check-in/check-out times to inflate hours or frame others
3. Exports falsified data via [9] Google Sheets integration or [12] sheet_pull
Chain 3: Production Information Disclosure
1. Attacker accesses [5] debug toolbar at /__debug__/ in production
2. Extracts SECRET_KEY, database credentials, internal paths, SQL query patterns
3. Uses [22] hardcoded database password if docker-compose is deployed as-is
4. Gains direct database access, exfiltrates or modifies all data
---
VERDICT
This application is NOT safe to deploy in its current state.Must Fix Immediately (Pre-Deployment Blockers):
1. [1] Credentials in URL – Move authentication to HTTP headers (Authorization: Basic or Bearer). Never accept credentials in query strings.
2. [6] Horizontal privilege escalation – Add user-level authorization: verify request.user.id == user_input or implement proper role-based scoping.
3. [12] Unauthorized mass data access – Add permission checks before returning all users. Implement role-based filtering (e.g., admins see all, regular users see only themselves).
4. [13] CSV injection – Escape all fields with a CSV library (Python's csv.writer) or prefix formula characters (=, +, -, @) with a single quote.
5. [17] API tokens in URLs – Use Authorization: Bearer <token> headers for API authentication.
6. [5] Debug toolbar in production – Wrap the debug toolbar URL inclusion in if settings.DEBUG: and ensure DEBUG is False in production.
7. [22] Hardcoded database password – Use secrets management (environment variables, Docker secrets, or a vault). Never commit credentials.
8. [23] DOM XSS – Use textContent instead of innerHTML, or sanitize with DOMPurify before rendering user-controlled data.
Risk Summary:
• Critical: Credential leakage and mass data exfiltration are trivially exploitable by any user or external observer.
• High: Privilege escalation allows users to manipulate others' records; CSV injection enables code execution on administrator machines.
• Configuration: Debug tooling and hardcoded secrets expose the entire application in production.
Recommendation:
Do not deploy until findings [1], [5], [6], [12], [13], [17], [22], and [23] are remediated and verified via re-scan and manual code review.
---