Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2025-48868

CVE-2025-48868: Horilla HRMS RCE Vulnerability

CVE-2025-48868 is a remote code execution flaw in Horilla HRMS 1.3.0 caused by unsafe eval() usage. Authenticated attackers can execute arbitrary commands on the server. This article covers technical details, impact, and mitigation.

Published:

CVE-2025-48868 Overview

CVE-2025-48868 is an authenticated Remote Code Execution (RCE) vulnerability in Horilla, a free and open source Human Resource Management System (HRMS). The flaw affects Horilla version 1.3.0 and stems from unsafe use of Python's eval() function on a user-controlled query parameter inside the project_bulk_archive view. Privileged users such as administrators can execute arbitrary system commands on the host running Horilla. The vulnerability is tracked under [CWE-95] (Improper Neutralization of Directives in Dynamically Evaluated Code). Horilla version 1.3.1 contains the official fix.

Critical Impact

Authenticated administrators can achieve full remote code execution on the Horilla server, including blind exploitation when Django DEBUG=False, leading to complete host compromise.

Affected Products

  • Horilla HRMS 1.3.0
  • Deployments using Django with DEBUG=True (output returned in HTTP response)
  • Deployments using Django with DEBUG=False (exploitable via blind payloads such as reverse shells)

Discovery Timeline

  • 2025-09-24 - CVE-2025-48868 published to the National Vulnerability Database (NVD)
  • 2025-09-29 - Last updated in NVD database

Technical Details for CVE-2025-48868

Vulnerability Analysis

The vulnerability exists in the project_bulk_archive view inside project/cbv/projects.py. The view passes a user-controlled query parameter into Python's eval() without sanitization or type enforcement. Because eval() executes arbitrary Python expressions, an attacker can call functions such as __import__('os').system(...) to spawn shell commands under the Horilla process account. Exploitation requires authentication with privileges that can reach the bulk archive action, typically an administrative role.

When Django runs with DEBUG=True, exceptions returned during evaluation reveal command output directly in the HTTP response, simplifying interactive exploitation. With DEBUG=False, attackers pivot to blind execution by issuing payloads that initiate outbound connections, such as reverse shells, achieving the same level of code execution without immediate response visibility.

Root Cause

The root cause is direct evaluation of attacker-controlled input through eval(). Horilla used eval() to convert query string data into a Python value during bulk archive processing. Safe alternatives such as ast.literal_eval(), explicit boolean parsing, or strict type casting were not in place.

Attack Vector

The attack vector is network-based through the authenticated HTTP interface. An attacker with administrative session cookies submits a crafted POST request to the bulk archive endpoint with a malicious value in the targeted query parameter. The server evaluates the expression and executes the embedded Python, providing arbitrary command execution.

python
# Security patch excerpt from project/cbv/projects.py
# Source: https://github.com/horilla-opensource/horilla/commit/b0aab62b3a5fe6b7114b5c58db129b3744b4d8cc
                    "attrs": """
                        id="archiveProject"
                        style="cursor: pointer;"
+                       onclick="validateProjectIds(event);"
+                       data-action="archive"
                        """,
                },
                {
                    "action": _("Un-archive"),
                    "attrs": """
                        id="unArchiveProject"
                        style="cursor: pointer;"
+                       onclick="validateProjectIds(event);"
+                       data-action="unarchive"
                        """,
                },

The patch replaces the dynamic eval()-based flow with discrete, explicit endpoints (project-bulk-archive and project-bulk-delete) bound through HTMX attributes, removing the dependency on evaluating raw query input.

Detection Methods for CVE-2025-48868

Indicators of Compromise

  • POST requests to /project-bulk-archive containing Python expressions such as __import__, os.system, subprocess, or eval in the is_active parameter.
  • Unexpected child processes of the Horilla Django/Gunicorn worker (for example, sh, bash, curl, wget, python -c).
  • Outbound network connections from the Horilla host to unfamiliar IP addresses or ports, consistent with reverse shell callbacks.
  • New or modified files in writable Horilla directories that were not deployed by the release pipeline.

Detection Strategies

  • Inspect Django access logs for the project_bulk_archive endpoint and flag requests whose parameters contain Python syntax or non-boolean values.
  • Apply application-layer rules in a Web Application Firewall (WAF) that block reserved Python tokens in HTTP parameters destined for Horilla.
  • Correlate Horilla web requests with endpoint process telemetry to identify shell or interpreter execution chained from the Python worker.

Monitoring Recommendations

  • Enable verbose request logging for authenticated administrative endpoints and forward logs to a centralized analytics platform.
  • Monitor for anomalous egress traffic originating from the Horilla server, especially to non-corporate destinations.
  • Alert on creation of new privileged users, scheduled tasks, or cron entries on the Horilla host following administrative activity.

How to Mitigate CVE-2025-48868

Immediate Actions Required

  • Upgrade Horilla to version 1.3.1, which removes the unsafe eval() call in the bulk archive flow.
  • Set Django DEBUG=False in production to prevent exception-based information disclosure if upgrade is delayed.
  • Audit administrative accounts and rotate credentials for any users with access to the project bulk archive functionality.
  • Review recent web and process logs for indicators of prior exploitation.

Patch Information

The fix is delivered in Horilla 1.3.1 via commit b0aab62b3a5fe6b7114b5c58db129b3744b4d8cc. Refer to the Horilla GitHub Security Advisory GHSA-h6qj-pwmx-wjhw for the full vendor advisory.

Workarounds

  • Restrict network access to the Horilla administrative interface using IP allowlisting or VPN-only access until the upgrade is applied.
  • Remove or downgrade administrative privileges from accounts that do not require bulk project management.
  • Deploy a reverse proxy or WAF rule that rejects POST requests to project-bulk-archive containing characters outside a strict boolean allowlist (true/false).
bash
# Example: Upgrade Horilla to the patched release
pip install --upgrade horilla==1.3.1

# Verify the installed version
python -c "import horilla; print(horilla.__version__)"

# Ensure Django DEBUG is disabled in production settings
export DJANGO_DEBUG=False

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.