CVE-2026-23873

9.0 CRITICAL

📋 TL;DR

CVE-2026-23873 is a CSV injection vulnerability in hustoj's contest rank export functionality that allows attackers to embed Excel formulas in nickname fields. When administrators export and open these rank lists in Microsoft Excel, the formulas execute, potentially leading to remote code execution on the administrator's machine. This affects all hustoj installations where administrators export contest rankings.

💻 Affected Systems

Products:
  • hustoj
Versions: All versions
Operating Systems: Linux, Windows (via Excel on administrator side)
Default Config Vulnerable: ⚠️ Yes
Notes: Vulnerability exists in default configuration. Requires both PHP backend (contestrank.xls.php and admin/ranklist_export.php) and administrator using Microsoft Excel to open exported files.

📦 What is this software?

⚠️ Risk & Real-World Impact

🔴

Worst Case

Full remote code execution on administrator's Windows machine through Excel formula execution, leading to complete system compromise, data exfiltration, or lateral movement.

🟠

Likely Case

Data exfiltration from administrator's machine through Excel formulas that can access local files or network resources, or denial of service through malicious formulas.

🟢

If Mitigated

No impact if administrators use text editors to view exports, have Excel security settings that block formula execution, or if nickname sanitization is implemented.

🌐 Internet-Facing: MEDIUM - Requires attacker to have contest participant account and administrator to export/open the file, but exploit chain is straightforward.
🏢 Internal Only: HIGH - Internal attackers with participant accounts can target administrators who regularly export rankings.

🎯 Exploit Status

Public PoC: ⚠️ Yes
Weaponized: LIKELY
Unauthenticated Exploit: ✅ No
Complexity: LOW

Exploit requires authenticated participant account to set malicious nickname, then administrator must export and open the file in Excel. CSV injection techniques are well-documented and weaponization is straightforward.

🛠️ Fix & Mitigation

✅ Official Fix

Patch Version: None

Vendor Advisory: https://github.com/zhblue/hustoj/security/advisories/GHSA-gqwv-v7vx-2qjw

Restart Required: No

Instructions:

No official patch available. Monitor GitHub repository for updates. Consider implementing input sanitization as described in workarounds.

🔧 Temporary Workarounds

Input Sanitization Patch

linux

Add CSV injection protection by sanitizing nickname input before export

Modify contestrank.xls.php and admin/ranklist_export.php to prepend apostrophe to nickname fields: $nickname = "'" . htmlspecialchars($nickname, ENT_QUOTES);

Excel Safe Mode Configuration

windows

Configure Excel to open CSV files in safe mode that prevents formula execution

Group Policy: Computer Configuration > Administrative Templates > Microsoft Excel 2016 > Excel Options > Security > Trust Center > Block execution of potentially dangerous functions

🧯 If You Can't Patch

  • Train administrators to never open exported rank files directly in Excel - use text editors or import as text-only data
  • Implement web-based rank viewing instead of Excel exports, or export as PDF instead of XLS

🔍 How to Verify

Check if Vulnerable:

Set nickname to formula like =cmd|'/c calc'!A0 in contest, export rank list as admin, open in Excel - if calculator opens, system is vulnerable.

Check Version:

Check hustoj version in source code or database: grep -r 'OJ_VERSION' /var/www/html/hustoj/ || Check README or changelog files

Verify Fix Applied:

After implementing sanitization, test with same payload - formula should display as text starting with apostrophe instead of executing.

📡 Detection & Monitoring

Log Indicators:

  • Nickname fields containing Excel formula patterns (=, @, +, -) in user registration/update logs
  • Large nickname entries or special characters in nickname fields

Network Indicators:

  • Unusual export activity patterns
  • Multiple rank export requests from same user

SIEM Query:

source="hustoj" AND (nickname="=*" OR nickname="@*" OR nickname="+*" OR nickname="-*")

🔗 References

📤 Share & Export