GHSA-qv4m-m73m-8hj7: NotrinosERP: Authenticated arbitrary file upload leads to remote code execution via HRM employee "Documents" (doc_file)
Summary
An authenticated user with the HR "Manage Employees" permission (SA_EMPLOYEE) can upload a file with an arbitrary extension through the employee Documents tab. The handler writes the raw client-supplied filename — extension intact — into a web served directory with no extension, MIME, or content validation, so a .php file is stored under the web root and executes as code, yielding remote code execution on the server.
Details
The document-upload branch in hrm/manage/employees.php (function tab_documents()) moves the uploaded file using the client filename verbatim:
// hrm/manage/employees.php -> tab_documents() (HEAD lines 597-602; release 1.0.0 lines 568-573)
$upload_dir = company_path().'/documents/employees';
if (!file_exists($upload_dir))
mkdir($upload_dir, 0777, true);
$file_path = $upload_dir.'/'.$employee_id.'_'.time().'_'.$_FILES['doc_file']['name'];
if (!move_uploaded_file($_FILES['doc_file']['tmp_name'], $file_path)) { ... }
There is no extension allow-list, getimagesize(), MIME check, or content inspection on this path. Contrast this with the profile photo (pic) upload in the *same file*, which validates image type/extension/size, and with core includes/ui/attachment.inc, which deliberately generates a random extension-less name (uniqid()) with a comment warning that client filenames must never be trusted. The document handler ignores that established safe pattern.
Reachability of the written file:
- company_path() resolves under the web root; config.default.php sets
$comp_path = $path_to_root.'/company', so uploads land in company/0/documents/employees/.
- The only .htaccess in the project is the repo-root one, which denies .inc/.po/.sh/.pem/.sql/.log
only — it does not block .php and does not cover company/.
- The stored path is then echoed unescaped into a clickable "View" link
(hrm/includes/ui/employee_ui.inc lines 153-154 — file_path concatenated straight into href),
handing the attacker the exact URL of the shell (and creating a secondary
Details
Original advisory: https://github.com/advisories/GHSA-qv4m-m73m-8hj7
More from GitHub Security Advisories
- criticalGHSA-g936-7jqj-mwv8: TSDProxy: Internal proxy auth token forwarded to backend services enables management API …2026-07-10
- highGHSA-fpg8-7664-jc5q: melange: Incomplete package integrity verification allows data section substitution2026-07-10
- mediumGHSA-48rx-c7pg-q66r: Excon does not redact additional sensitive/risky headers when following redirects2026-07-10
- highGHSA-h4g2-xfmw-q2c9: Clauster: Non-loopback deployments can serve the dashboard unauthenticated when auth.enab…2026-07-10
- mediumGHSA-rqq5-2gf9-4w4q: Secure Headers: CSP directive injection via sandbox, plugin_types, and report_to when giv…2026-07-10