signageOS Zero-Day: Unauthenticated Command Injection
Femto Security identified an unauthenticated zero-day command injection flaw in the signageOS Box package upload endpoint yielding remote code execution.

Femto Security identified an unauthenticated zero-day command injection flaw in the signageOS Box package upload endpoint yielding remote code execution.

The Femto Security Vulnerability Research Team discovered a critical unauthenticated remote code execution vulnerability in the signageOS digital signage management platform. Researched and documented by security researcher Mahmoud Amin, this vulnerability allowed an unauthenticated remote attacker to execute arbitrary operating system commands on the backend serverless infrastructure supporting the signageOS Box web console (box.signageos.io).
The vulnerability resided within an externally accessible, unauthenticated API endpoint, POST /packages/upload, hosted on the box.signageos.io control plane. The endpoint accepted a query-string parameter named packageName and embedded its value directly into an operating system shell command line without escaping, parameterization, or input allow-list validation. The backend application, implemented in Node.js, executed this synthesized command string via the child_process.exec API inside an AWS Lambda serverless runtime environment.
Vulnerability Snapshot
Because the command string was executed through a system shell interpreter (/bin/sh -c), shell metacharacters such as a semicolon (;) allowed an unauthenticated attacker to terminate the intended command and execute arbitrary operating system commands. Furthermore, the application error handler captured standard error (stderr) generated by command execution and reflected it directly into the HTTP 500 JSON response body returned to the client. This architectural behavior transformed what would otherwise have been a blind injection vector into a fully synchronous, in-band execution channel requiring only a single HTTP request.
The underlying AWS Lambda execution environment contained sensitive process environment variables, including the function's AWS Identity and Access Management (IAM) execution role credentials and static Amazon Simple Storage Service (S3) key pairs. Access to these credentials presented a direct path toward backend cloud storage and customer data access. Under the Common Vulnerability Scoring System (CVSS) version 4.0, this vulnerability was rated with a base score of 9.3 (Critical) and the vector string AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H. Following coordinated disclosure, the vendor implemented an ingress validation remediation within two days.
The security research focused on the core web and API assets of the signageOS platform. signageOS provides unified infrastructure and management software for digital signage networks, system-on-chip displays, and external media players across transportation hubs, retail environments, and enterprise facilities. The primary in-scope assets included:
Submitted report with reproducible PoC and remediation advice through signageOS bug-bounty program.
Vendor deployed ingress validation rejecting shell metacharacters in packageName.
box.signageos.io: The customer-facing Box management console and administrative control plane.
api.signageos.io: The underlying REST API backend supporting device management and platform services.
Digital signage management platforms routinely ingest binary artifacts, software applets, media files, and native Android application package (.apk) files intended for deployment to physical digital signage players. Ingesting untrusted binary packages and parsing them with external command-line utilities presents a critical attack surface when input parameters are handled unsafely at the operating system boundary.
The root cause of this vulnerability was improper neutralization of special elements used in an OS command (classified under CWE-78: OS Command Injection), accompanied by CWE-209 (Generation of Error Message Containing Sensitive Information).
During package processing, the server-side Node.js application inspected uploaded Android application packages to determine their application type by invoking the Android Asset Packaging Tool (aapt2). The application constructed the execution string by interpolating user-controlled parameters into a command template:
child_process.exec(
`/var/task/tools/aapt2 dump badging /tmp/package_${ownerOrganizationUid}_android_${packageName}_${sha256}_${ts}.apk`
);In Node.js, invoking child_process.exec spawns a full system shell (/bin/sh -c "<string>"). Because the application performed direct string interpolation of the user-supplied packageName and ownerOrganizationUid query parameters without sanitization or escaping, standard shell control characters were interpreted by the shell interpreter rather than treated as literal filename components.
In addition, the application's unhandled exception wrapper caught errors thrown by child_process.exec. When a process returned a non-zero exit status, Node.js generated an Error object containing the complete command line and its stderr stream. The application serialized this error object directly into the JSON response body returned to the HTTP client, exposing internal paths (such as the Lambda root directory /var/task/) and echoing command output directly to the caller.
The exploitation chain operated unauthenticated over standard HTTPS requests to box.signageos.io. Mapping of the front-end package upload workflow revealed that the POST /packages/upload endpoint accepted requests without requiring session cookies, API tokens, or user authentication headers.
Attacker sends POST /packages/upload with malformed APK packageFile and arbitrary packageName query parameter without authentication.
Server interpolates unescaped packageName into aapt2 command string passed directly to child_process.exec (spawning /bin/sh -c).
Injected metacharacters (;) execute arbitrary OS commands within the production AWS Lambda sandbox runtime.
Verbose HTTP 500 error handler captures raw command stderr and returns output directly in the JSON response body.
When an unauthenticated request containing a small, malformed .apk payload was transmitted to the endpoint, the application attempted to execute aapt2 dump badging against the temporary file path in /tmp/. Because the file was not a valid Android archive, aapt2 failed with a non-zero exit status, causing the server to return an HTTP 500 response containing the raw execution string:
Command failed: /var/task/tools/aapt2 dump badging /tmp/package_{ownerOrganizationUid}_android_{packageName}_{sha256}_{timestamp}.apkBecause the packageName value was embedded directly into the synthesized filename, an attacker could supply shell control metacharacters (such as ;) to break out of the aapt2 command line and append arbitrary shell commands. Furthermore, by redirecting output to the standard error stream (1>&2), output from the injected command was captured by the Node.js execution error handler and reflected directly inside the HTTP 500 JSON response body.
All validation activities were conducted following strict safety boundaries: testing was non-destructive and designed exclusively to prove the presence of command execution without extracting secret values or altering server-side state. Each test was executed without authentication, supplying a minimal ~282-byte dummy archive as the packageFile multipart field while adjusting only the packageName query parameter.
To establish baseline execution behavior and confirm the sink structure, an initial baseline request was sent with standard alphanumeric values:
POST /packages/upload?packageName=test&ownerOrganizationUid={ORG} HTTP/1.1
Host: box.signageos.io
Content-Type: multipart/form-data; boundary=----x
------x
Content-Disposition: form-data; name="packageFile"; filename="fake.apk"
Content-Type: application/octet-stream
<~282 bytes of zip>
------x--The server returned an HTTP 500 response within approximately 0.3 seconds. The response body echoed the complete aapt2 ... _android_test_ ... .apk command line, confirming the exact sink location and parameter placement.
To confirm that the shell parsed and executed chained command sequences, a time-delay payload was submitted via packageName = test;sleep 8;x (URL-encoded as test%3Bsleep%208%3Bx):
The server returned an HTTP 500 response after approximately 8.6 seconds, demonstrating an ~8.3-second delay over the baseline response time. The semicolon successfully terminated the aapt2 invocation and directed the shell to execute sleep 8.
To establish that responses reflected live execution rather than cached responses or replays, a distinct marker was echoed to standard error using packageName = test;echo SPECTREVERIFY7391 1>&2;x:
The server returned an HTTP 500 response containing the string SPECTREVERIFY7391 within the JSON response body. Because standard output was redirected to standard error (1>&2), the Node.js exec error handler incorporated the output into the thrown exception and reflected it directly back to the HTTP client.
To identify the execution privileges and operating system sandbox, process identity was verified using packageName = test;id 1>&2;x:
The server returned an HTTP 500 response containing the following process identity output:
uid=993(sbx_user1051) gid=990 groups=990The sbx_user1051 user identifier is the canonical AWS Lambda execution sandbox user, confirming execution directly within the production Lambda environment.
To maintain safety and tenant confidentiality, bulk environment dumps were deliberately avoided. While executing env would have exposed all process environment variables, validation was strictly limited to verifying the existence of environment variable names without reading, printing, or logging their values. The following variable names were confirmed present in the execution environment:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN
AWS_S3_ACCESS_KEY
AWS_S3_SECRET
AWS_S3_BUCKET
Confirming that these variable names existed within the process environment demonstrated credential exposure risks without accessing any sensitive customer or platform secrets.
The security impact of this vulnerability encompasses full serverless environment compromise:
Unauthenticated Remote Code Execution: An attacker could execute arbitrary operating system commands within the production box.signageos.io backend via a single unauthenticated HTTP request without requiring user interaction, administrative privileges, or valid credentials.
Credential Exposure and Cloud Storage Access: The execution environment contained temporary IAM execution role credentials alongside static Amazon S3 credentials (AWS_S3_ACCESS_KEY, AWS_S3_SECRET, AWS_S3_BUCKET). Because the signageOS platform references public, user-data, and provisioning S3 buckets, exposure of these keys established a path toward unauthorized access to backend storage and tenant customer data.
Lateral Movement and Warm Container Reuse: Injected processes could interact with AWS Lambda runtime APIs and metadata loopback endpoints from within the sandbox. Furthermore, because AWS Lambda reuses warm container instances across sequential invocations, an attacker could potentially achieve persistence across multiple customer requests processed by the same container instance.
The vulnerability was evaluated under CVSS 4.0 with a score of 9.3 (Critical): AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H.
The vulnerability was reported to the signageOS bug bounty program on 2026-07-04 with full proof-of-concept details. On 2026-07-06, re-testing confirmed that the vendor had deployed a remediation.
Following the fix, requests containing shell metacharacters in the packageName parameter were rejected at ingress with an HTTP 400 response:
{
"message": "Invalid packageName. Only letters, digits, '.', '_' and '-' are allowed."
}Subsequent tests confirmed that payloads containing sleep, echo, and id commands were rejected and no longer executed.
To eliminate command injection risks across serverless and web application workloads, organizations should implement the following controls:
Avoid Shell Spawning via Argument Arrays: Do not build shell command lines through string interpolation. Use parameterized execution APIs such as child_process.execFile in Node.js, which bypass the shell interpreter and pass arguments directly to the binary as an array:
child_process.execFile('/var/task/tools/aapt2', ['dump', 'badging', filePath]);Enforce Ingress Allow-Lists: Validate all user-supplied input against strict allow-lists (such as ^[A-Za-z0-9._-]+$) before using values in file paths or external process invocations.
Suppress Internal Error Diagnostics: Do not return raw command lines, standard error streams, or internal file paths to clients (mitigating CWE-209). Log diagnostic details internally and return generic error responses to external callers.
Enforce Principle of Least Privilege and Credential Hygiene: Restrict AWS Lambda execution role permissions to the minimum necessary scope. Avoid storing long-lived static S3 access keys within environment variables, preferring dynamically assumed IAM roles. Any credentials exposed within an execution environment during an active vulnerability window must be rotated immediately.
This finding highlights several broader architectural and offensive security lessons:
File Ingestion Workflows are Command Injection Vectors: Any server-side workflow that processes uploaded files using external command-line tools (such as aapt2, ffmpeg, unzip, pdfinfo, or ImageMagick) requires rigorous parameterization to avoid shell injection flaws.
Verbose Error Handlers Accelerate Exploitation: Reflecting standard error output to clients eliminates the complexity of blind command injection, transforming blind vulnerabilities into synchronous, in-band execution channels.
Safe Verification Demonstrates Impact: Non-destructive validation using benign commands (sleep, unique marker reflection, and id) successfully confirms command execution without compromising infrastructure integrity or reading sensitive customer data.
The Femto Security Vulnerability Research Team thanks the signageOS security engineering team for their rapid communication, professional collaboration, and prompt two-day remediation of this critical vulnerability.
Concerned about similar zero-day risks or logic flaws in your software? Femto Security performs rigorous offensive code reviews, red teaming, and vulnerability assessments.