Malcolm: RCE via unrestricted .php upload in the file-upload component
An authenticated user uploads a .php file to the file-upload component and requests it to execute arbitrary code as www-data inside the container.
Advisory ID: TP-2026-022
Product: Malcolm (network traffic analysis suite built on Zeek, Arkime and OpenSearch)
Vulnerability type: Unrestricted upload of file with dangerous type (CWE-434)
CVE: CVE-2026-55676
CVSS 3.1: 8.8 (High) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Affected versions: <= v26.06.0
Fixed in: v26.06.1
Vendor advisory: GHSA-8cvp-m7pg-qrp7
Reported: 13 June 2026
Summary
Malcolm is a network traffic analysis suite that, among other things, accepts uploaded PCAP and log files for analysis. The FilePond PHP backend of the file-upload component checks the file type against an allowlist that is empty by default, which turns the type check into a no-op and accepts any extension. The filename sanitiser preserves the .php extension, and the component's own nginx configuration routes any URL ending in .php to php-fpm in the same container. An authenticated user uploads a .php file and then requests it, which executes arbitrary code as www-data. turingpoint verified the flow and reported it responsibly; the vendor fixed it in v26.06.1.
Root cause
The backend accepts uploads at POST /server/php/submit.php with no type allowlist, because ALLOWED_FILE_FORMATS is an empty array by default and the type check becomes a no-op (file-upload/php/config.php:16). The filename sanitiser cleans the base name and the extension separately and rejoins them, so shell.php stays shell.php (FilePond.class.php:43). Committed files land in /var/www/upload/server/php/files (config.php:7), which the component's own nginx routes to php-fpm for any URL ending in .php (file-upload/nginx/sites-available/default:13), while the Malcolm front-door nginx proxies /server/php there behind a single authentication check (nginx/nginx.conf:155). In RBAC mode (NGINX_AUTH_MODE=keycloak plus ROLE_BASED_ACCESS=true, non-default) the endpoint is already reachable by the low-privilege ROLE_UPLOAD role (nginx/lua/nginx_auth_helpers.lua:71), so an upload-only account gains code execution beyond its intended capability. An authenticated GET /server/php/files/<name>.php then executes the uploaded file as www-data.
Proof of Concept
As an authenticated user:
POST /server/php/submit.php (multipart/form-data, filename="shell.php")
-> 200, file stored as files/shell.php
GET /server/php/files/shell.php?c=id
-> uid=1000(www-data) gid=1000(www-data)
The empty allowlist lets the .php file through, the sanitiser keeps the extension, and the component's own nginx routes the subsequent GET to php-fpm, which executes the file as www-data.
Impact
- Arbitrary code execution as
www-datainside the file-upload container. - Privilege escalation from an upload-only role (
ROLE_UPLOAD) to code execution in RBAC mode. - Read access to uploaded capture data and the admin password hash (
MALCOLM_PASSWORD, crackable offline). - Write access to the host-mounted directories that feed the analysis pipeline.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.
