By: DF Pentest Team (Datafarm Co., Ltd. — Thailand)
Authors: Thanasin Luangpipat, Natchanon Jaengsuwan, Navapon Premkasem, Suebpong Sittichotpong
Introduction
In telecommunications and Internet Service Provider (ISP) environments, managing customer premises equipment (CPE) such as routers and modems is facilitated by Auto Configuration Servers (ACS), which communicate with devices via the TR-069 (CWMP) protocol.
GenieACS is an open-source ACS used to provision and manage these devices. During a recent security assessment, our team analyzed the inner workings of GenieACS. This analysis led to the discovery of a vulnerability chain assigned CVE-2025–56015 that allows an unauthenticated user to achieve Remote Code Execution (RCE) on the server.
Affected Version: GenieACS v1.2.13 (and potentially prior versions).
Note: This vulnerability has been addressed and patched in the current release.
This article details the process of identifying these behaviors, how they interact, and the method used to exit the application’s internal sandbox.
Phase 1: Reconnaissance and the Unauthenticated APIs
The research began by setting up a local instance of GenieACS using Docker (based on the test environment from https://github.com/GeiserX/genieacs-docker) to observe its available services. GenieACS exposes several services on different ports, notably:
- Port 7547: The ACS interface (CWMP) for device communication.
- Port 7557: The Northbound Interface (NBI), a RESTful API used for management and integration.
- Port 7567: The File Server (FS) for hosting firmware and configuration files.
We focused our initial observations on the NBI (Port 7557) to understand how GenieACS handles authentication for its REST API.
During testing, we observed that certain endpoints did not require authentication. We were able to interact with the API by sending unauthenticated curl requests.
Information Disclosure:
By querying the /users/ endpoint, the server returned account information, including password hashes, salts, and role assignments:
[Example code for /users/ endpoint]
[
{
"_id": "admin",
"roles": "admin",
"password": "60d3eb2af99f…",
"salt": "708e343a7a4d…"
}
]
We also noted the ability to list files via the NBI API (/files/) and download files directly from the file server (Port 7567) without providing credentials. For example, using wget:
[Example code for wget]
$ wget 'http://myhost:7567/SCR-20250623-qjoi.png'
- 2025–06–27 16:31:23 - http://myhost:7567/SCR-20250623-qjoi.png
HTTP request sent, awaiting response… 200 OK
State Modification & Code Analysis:
We then tested whether this behavior extended to PUT requests. We found that it is possible to create and modify Provisions (scripts executed by the ACS) and Presets (the triggers/schedules for those scripts) through the NBI API without authentication.
By analyzing the source code in lib/nbi.ts, we discovered that the Northbound Interface (NBI) API handler completely lacks authentication and authorization checks. For instance, the handler processes requests directly based on regex matches:
[Example code from lib/nbi.ts]
} else if (PROVISIONS_REGEX.test(url.pathname)) {
// …
if (request.method === "PUT") {
const object = {
_id: provisionName,
script: body.toString(),
};
// …
await collections.provisions.replaceOne({ _id: provisionName }, object, {
upsert: true,
});
Similar logic exists for the PRESETS_REGEX, allowing unauthenticated users to upload malicious provisioning scripts and create presets to trigger them automatically. This fundamental misconfiguration allows for unauthenticated script injection into the system.
Phase 2: The Sandbox Escape
With the ability to inject provisioning scripts, we proceeded to analyze how GenieACS executes them.
GenieACS allows administrators to define provisioning logic using JavaScript. To run these dynamic scripts, GenieACS executes them within a JavaScript sandbox environment. This sandbox restricts the script’s access to the underlying operating system and core Node.js modules. Attempting to call require(‘child_process’) or accessing the global process object directly results in an error.
To test the sandbox restrictions, we utilized a test debug endpoint at /debug/provision that executes code inside the sandbox environment. We observed that accessing process.env directly is not allowed, as the global process object is unavailable within the sandboxed context.
To exit the sandbox, we analyzed the exposed objects.
Prototype Traversal & Code Analysis
In JavaScript, functions and objects inherit properties through prototypes. If a sandbox environment shares references with the host Node.js environment, it may be possible to use prototype traversal to access the host context.
Looking into lib/sandbox.ts, GenieACS creates a restricted environment using vm.createContext. However, it inadvertently exposes functions from the main Node.js process directly into the sandbox context:
[Example code from lib/sandbox.ts]
Object.defineProperty(context, "declare", { value: declare });
Object.defineProperty(context, "clear", { value: clear });
Object.defineProperty(context, "commit", { value: commit });
Object.defineProperty(context, "ext", { value: ext });
Object.defineProperty(context, "log", { value: log });
We focused on the declare() function, which is exposed to the sandbox but instantiated in the host environment. Because it retains its original prototype chain, we applied a prototype traversal method by accessing the constructor of its constructor:
[Example Sandbox Escape Code]
// 'declare' is available in the sandbox
let funcConstructor = declare.constructor.constructor;
The execution flow of this chain is as follows:
1. declare is a function within the sandbox.
2. declare.constructor returns the Function constructor belonging to the sandbox context.
3. declare.constructor.constructor traverses the prototype chain and returns the global Function constructor of the main Node.js process.
By obtaining the main Node.js process’s Function constructor, we bypassed the sandbox boundary. This allows for the dynamic evaluation of JavaScript code within the host environment.
A proof-of-concept payload utilizing this method is:
[Example RCE Payload]
declare.constructor.constructor("return process")().mainModule.require("child_process").execSync("id > /tmp/pwned");
Phase 3: Chaining the Behaviors for RCE
At this stage, we identified two behaviors:
1. Unauthenticated creation of Provisions and Presets.
2. A Sandbox Escape leading to RCE.
Post-Auth RCE (Authentication Required):
With authentication, one can directly execute Provision scripts through the UI API endpoint /api/devices/{device_id}/tasks to obtain shell access. Interestingly, if a similar task execution request is sent through the unauthenticated NBI, it is only added to the queue but not immediately executed.
Pre-Auth RCE (Unauthenticated RCE):
To achieve execution without authentication, the unauthenticated features must be chained together.
By combining these behaviors, a script can be set to execute automatically without prior authentication.
The sequence of operations is as follows:
Step 1: Script Upload
Using the NBI API (PUT /provisions/{provision_name}), a JavaScript payload (the sandbox escape code) is uploaded.
Step 2: Event Mapping
Using the NBI API (PUT /presets/{preset_name}), a new preset is created. This preset is configured to execute the uploaded provision when a specific event occurs, such as a “Periodic” update.
Step 3: Trigger Execution
To initiate the event, a script can be used to simulate a CPE device. A Device Inform SoapXPC message is sent to the ACS CWMP interface (Port 7547).
When the ACS processes the simulated device’s “Periodic” inform request, it evaluates its presets, identifies the newly created one, and executes the associated provisioning script. You will see that devices send Inform requests subsequently in the system (logging the inform event as “2 PERIODIC”).
The script then exits the sandbox, executing the payload on the server.
Proof of Concept (PoC)
To demonstrate the full execution of this attack chain, a complete Python exploit script has been developed. The script automates the process of injecting the malicious provision, mapping it to a preset, and simulating the CWMP inform request to trigger the reverse shell.
The full Proof-of-Concept exploit code is available on GitHub:
https://github.com/e1st/CVE-2025-56015
The execution of the exploit and the resulting reverse shell can be seen below:

Conclusion
CVE-2025–56015 illustrates the effects of chaining an access control oversight with a sandbox escape. The combination allows API access to interact directly with the internal evaluation engine. Since this vulnerability impacts version 1.2.13 but has been successfully patched in the current versions of GenieACS, users are encouraged to ensure their instances are up to date.
This analysis is provided to document the vulnerability and assist in understanding the mechanics of these specific behaviors.
Proactive Monitoring with Personar Cyber News
Tracking newly discovered vulnerabilities such as CVE-2025–56015 is a continuous requirement for security teams. To assist organizations in maintaining visibility over the threat landscape, Datafarm Co., Ltd. is actively expanding the Cyber News feature within the Personar service (https://personar-th.com/).
Currently, the platform provides active Dark Web Monitoring, tracking indicators of compromise, data leaks, ransomware claims, and threat actor discussions across the dark web, Tor forums, and Telegram.
To further empower security teams, the Personar platform will receive two major updates in the future to complete its intelligence offering:
1. Global CVE Feed: This future update will deliver real-time information on the latest vulnerabilities, including severity scores (CVSS) and impacted products, ensuring teams are immediately informed of critical issues like CVE-2025–56015.
2. Cyber Threat Intelligence (CTI): This update will map threat actor activities and attack techniques to the MITRE ATT&CK framework, providing insights into the threat groups and methodologies most likely to target a user’s specific sector.
By centralizing these intelligence sources, the evolving Personar platform enables organizations to proactively monitor emerging risks and respond to vulnerabilities before they can be exploited.