Nov 7, 2026·9 min read·0 visits
An object-level authorization bypass in Eclipse hawkBit's DDI controller (<= 1.0.3) allows any authenticated IoT device to enumerate and download arbitrary firmware artifacts belonging to other devices within the same tenant. Upgrade to version 1.0.4 to enforce strict device-to-artifact assignment validation.
CVE-2026-16454 is an object-level authorization bypass vulnerability (CWE-284, CWE-862) in Eclipse hawkBit versions 1.0.3 and prior. The flaw exists within the Direct Device Integration (DDI) REST controller (hawkbit-ddi-resource), where endpoints responsible for enumerating software module metadata and serving firmware binaries fail to verify whether the requested software module is assigned to the authenticated device. Consequently, any device with valid credentials (such as a TargetToken or GatewayToken) can enumerate software module identifiers and download arbitrary firmware artifacts across the entire tenant namespace.
Eclipse hawkBit is a domain-independent back-end framework designed for rolling out software updates to constrained edge devices, gateways, and IoT controllers. To support diverse deployment architectures, hawkBit exposes three primary interfaces: the Management API for administrative operations, the Device Management Federation (DMF) API for message-oriented integration via AMQP, and the Direct Device Integration (DDI) API. The DDI API (/{tenant}/controller/v1/{controllerId}) provides an HTTP REST polling interface that edge devices query directly to retrieve deployment actions, download firmware binaries, and submit installation status reports.
In Eclipse hawkBit versions 1.0.3 and earlier, the DDI API implementation within the hawkbit-ddi-resource module suffers from Broken Object Level Authorization (BOLA), tracked under CWE-284 (Improper Access Control) and CWE-862 (Missing Authorization). Under hawkBit's security model, an authenticated target device should only be permitted to access metadata and binary payloads for software modules explicitly linked to an active or installed deployment action for that specific controllerId. However, the DdiRootController class omits these object-level relationship checks across its metadata listing and artifact download handlers.
Because of this omission, authentication is verified at the tenant and target identity level, but authorization is not enforced at the resource level. Any device possessing valid DDI credentials—such as a device-specific TargetToken, a tenant-wide GatewayToken, or a valid client certificate—can query sequential softwareModuleId parameters to enumerate all software modules within its tenant. Furthermore, the device can download the corresponding firmware payloads regardless of device assignment.
While multi-tenant isolation remains intact—preventing a device in one tenant from accessing resources in another—the flaw eliminates horizontal access boundaries within a single tenant. In heterogeneous IoT environments where low-security edge sensors and high-value infrastructure gateways share a single hawkBit tenant, compromising a single peripheral device exposes the firmware binaries of all other device classes managed within that workspace.
The root cause of CVE-2026-16454 lies in two distinct design and implementation flaws within org.eclipse.hawkbit.ddi.rest.resource.DdiRootController.java. When a device interacts with the DDI API, the controller first resolves the device identity by calling findTarget(controllerId) and retrieves the requested software module via controllerManagement.getSoftwareModule(softwareModuleId). In vulnerable versions, the controller assumes that possessing a valid session for controllerId and knowing the softwareModuleId is sufficient authorization to access the module's contents.
The first flaw occurs in the getSoftwareModulesArtifacts method, which handles GET /{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts. This method resolves the Target and the SoftwareModule entities and immediately passes them to DataConversionHelper.createArtifacts(...) to construct the HTTP 200 response containing filenames, cryptographic hashes (MD5, SHA-1, SHA-256), file sizes, and download links. At no point does the method query controllerManagement to verify whether an active update Action or historical installation links target to softwareModule.
The second flaw resides in the downloadArtifact and downloadArtifactMd5 methods, which serve the raw firmware binary and its MD5 checksum file. In downloadArtifact, the only operation that checked for a valid deployment action between the target and the software module was a helper method named logDownload(...). However, the execution of logDownload(...) was conditionally bypassed whenever the incoming HTTP request contained a Range header:
final ActionStatus actionStatus = RequestResponseContextHolder.getHttpServletRequest().getHeader("Range") == null
? logDownload(RequestResponseContextHolder.getHttpServletRequest(), target, module.getId())
: null; // range request - could have too many - so doesn't check action, don't log action status, and don't publish eventsAs indicated by the inline developer comment, logDownload was skipped during HTTP byte-range requests to prevent database and event-bus flooding when devices downloaded firmware in small chunks. Because the authorization check (controllerManagement.getActionForDownloadByTargetAndSoftwareModule) was coupled inside logDownload—or omitted prior to streaming—any request containing a Range header bypassed action validation entirely and proceeded directly to FileStreamingUtil.writeFileResponse(...).
> [!NOTE]
> Even when the Range header was omitted, the architecture treated action lookup as a side effect of status logging rather than a mandatory security gate before initiating file input/output streams.
The vulnerability was remediated across two commits in the eclipse-hawkbit/hawkbit repository: commit 6cb34fd77f6a60cfb0ee5b379093593cbe56591a (PR #3156), which secured the binary and MD5 download endpoints, and commit 914b8b406bd77838cffbef80c1ea4cff5a15c710 (PR #3161), which secured the metadata enumeration endpoint.
In commit 6cb34fd77f6a60cfb0ee5b379093593cbe56591a, the developers decoupled the assignment validation check from the Range header condition in DdiRootController.java. Before streaming the artifact or writing the MD5 response, the controller now unconditionally invokes controllerManagement.getActionForDownloadByTargetAndSoftwareModule(...):
// Patched downloadArtifact logic in DdiRootController.java
// 1. Unconditionally verify that the software module is assigned to the requesting target
final Action action = Objects.requireNonNull(
controllerManagement.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), module.getId()));
// 2. Only log the download action status if the request is not a partial Range request
final ActionStatus actionStatus = getHttpServletRequest().getHeader("Range") == null
? logDownload(action)
: null;
result = writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(),
getHttpServletRequest(), getHttpServletResponse(),
...);If the target device does not have an assigned download action containing the specified softwareModuleId, getActionForDownloadByTargetAndSoftwareModule throws a SoftwareModuleNotAssignedToTargetException (or returns null, triggering Objects.requireNonNull), terminating the request before writeFileResponse or writeMD5FileResponse is reached.
In commit 914b8b406bd77838cffbef80c1ea4cff5a15c710, the metadata listing endpoint (getSoftwareModulesArtifacts) was updated to enforce assignment validation while preserving compatibility for devices querying metadata of already-installed modules:
@Override
public ResponseEntity<List<DdiArtifact>> getSoftwareModulesArtifacts(
final String tenant, final String controllerId, final Long softwareModuleId) {
final Target target = findTargetOrThrow(controllerId);
final SoftwareModule softwareModule = controllerManagement.getSoftwareModule(softwareModuleId);
// Verify that the module is part of an active action assigned to the device
try {
final Action action = Objects.requireNonNull(
controllerManagement.getActionForDownloadByTargetAndSoftwareModule(controllerId, softwareModuleId));
log.debug("getSoftwareModulesArtifacts({}, {}) for action {}", controllerId, softwareModuleId, action.getId());
} catch (final SoftwareModuleNotAssignedToTargetException e) {
// Fallback: Check if the module belongs to the distribution set currently installed on the target
controllerManagement.findInstalledActionByTarget(target)
.filter(action -> action.getDistributionSet().getModules().stream()
.map(SoftwareModule::getId).anyMatch(id -> id.equals(softwareModuleId)))
.ifPresentOrElse(
action -> log.debug("getSoftwareModulesArtifacts({}, {}) for installed action {}",
controllerId, softwareModuleId, action.getId()),
() -> {
// Neither assigned for download nor currently installed; deny access
throw e;
});
}
return new ResponseEntity<>(
createArtifacts(
target, softwareModule, artifactUrlHandler, systemManagement, new ServletServerHttpRequest(getHttpServletRequest())),
HttpStatus.OK);
}This two-tier check ensures that getSoftwareModulesArtifacts only returns artifact metadata if the requested softwareModuleId belongs to a pending update action or the currently installed distribution set for that specific controllerId. Both code paths in DdiRootController are completely covered by these fixes, closing the horizontal privilege escalation vector.
Exploiting CVE-2026-16454 requires network access to the Eclipse hawkBit DDI HTTP interface and valid authentication credentials for at least one target device within the target tenant. In standard IoT deployments, edge devices authenticate using a per-device TargetToken stored in non-volatile memory. An attacker who extracts this token from a single physical device (e.g., via UART/JTAG debugging or flash dump) can interact directly with the DDI API.
The attack proceeds in two phases: software module enumeration followed by binary exfiltration. Because softwareModuleId values are auto-incrementing integers generated by the database, the attacker iterates through integer values against the metadata endpoint:
GET /default/controller/v1/sensor-device-01/softwaremodules/102/artifacts HTTP/1.1
Host: hawkbit.example.internal:8080
Authorization: TargetToken a1b2c3d4e5f60123456789abcdef0123
Accept: application/jsonWhen the attacker probes an existing softwareModuleId belonging to the same tenant, the vulnerable server returns an HTTP 200 OK response containing the full artifact metadata array, including the exact filename and download URI:
[
{
"filename": "firmware-core-router-v2.4.bin",
"size": 15728640,
"hashes": {
"sha1": "3a0b41c6d3e8f192...",
"md5": "098f6bcd4621d373...",
"sha256": "5e884898da280471..."
},
"_links": {
"download": {
"href": "http://hawkbit.example.internal:8080/default/controller/v1/sensor-device-01/softwaremodules/102/artifacts/firmware-core-router-v2.4.bin"
}
}
}
]In the second phase, the attacker uses the discovered filename to download the unassigned firmware image. By supplying the Range: bytes=0- HTTP header, the request bypasses the logDownload action lookup in DdiRootController and streams the complete binary payload while simultaneously suppressing download status log entries in the database:
GET /default/controller/v1/sensor-device-01/softwaremodules/102/artifacts/firmware-core-router-v2.4.bin HTTP/1.1
Host: hawkbit.example.internal:8080
Authorization: TargetToken a1b2c3d4e5f60123456789abcdef0123
Range: bytes=0-The server responds with HTTP/1.1 206 Partial Content and streams the entire binary (bytes 0-15728639/15728640) to the attacker.
CVE-2026-16454 is rated Medium severity with a CVSS v3.1 base score of 4.3 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N). The vulnerability impacts confidentiality exclusively, with no direct mechanism to modify existing software modules, alter deployment assignments, or disrupt service availability on the hawkBit update server.
Despite the modest base score, the practical security impact depends heavily on how an organization structures its hawkBit tenants and what data is embedded within its firmware artifacts. In many enterprise IoT architectures, a single hawkBit tenant manages diverse device fleets—ranging from inexpensive, physically exposed environmental sensors to industrial gateways and core routing appliances. If an attacker extracts the TargetToken from a physically accessible sensor, CVE-2026-16454 allows them to download the firmware images of every high-privilege gateway or controller managed within that tenant.
Once exfiltrated, these firmware binaries can be unpacked and reverse-engineered offline. Attackers commonly analyze stolen firmware to extract proprietary business logic, hardcoded API credentials, private cryptographic keys, or undisclosed vulnerabilities (such as command injection or buffer overflows) in the gateway software. Furthermore, because the Range: bytes=0- header suppresses ActionStatus creation in DdiRootController, the unauthorized downloads do not appear in the target device's deployment history within the hawkBit Management UI.
As of the latest threat intelligence data, CVE-2026-16454 is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog, and no active exploitation campaigns have been observed in the wild. The Exploit Prediction Scoring System (EPSS) assigns this vulnerability a score of 0.00356 (29.53rd percentile), indicating a low probability of widespread automated exploitation.
The primary remediation is to upgrade Eclipse hawkBit to version 1.0.4 or later. Version 1.0.4 incorporates commits 6cb34fd77f6a60cfb0ee5b379093593cbe56591a and 914b8b406bd77838cffbef80c1ea4cff5a15c710, which enforce strict target-to-module assignment validation across all DDI artifact download and metadata endpoints.
For applications managing dependencies via Apache Maven, update the hawkbit-update-server or hawkbit-ddi-resource version in pom.xml:
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-update-server</artifactId>
<version>1.0.4</version>
</dependency>For containerized deployments, pull the patched container image from Docker Hub:
docker pull hawkbit/hawkbit-update-server:1.0.4If an immediate upgrade to version 1.0.4 is not operationally feasible, administrators should implement compensating controls at the architecture and network layers:
controllerId or client IP on /{tenant}/controller/v1/*/softwaremodules/* routes. This hinders automated brute-force enumeration of sequential softwareModuleId paths.GatewayToken credentials across broad device populations. Provision unique TargetToken credentials or mutual TLS (mTLS) client certificates per device so that compromised credentials can be individually revoked.CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Eclipse hawkBit Eclipse Foundation | <= 1.0.3 | 1.0.4 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-16454 (GHSA-92r3-p8c2-3fpx) |
| Weakness Class | CWE-862 (Missing Authorization) / CWE-284 (Improper Access Control) |
| Affected Component | DdiRootController (hawkbit-ddi-resource <= 1.0.3) |
| Attack Vector | Network (Authenticated DDI HTTP REST API) |
| CVSS v3.1 Score | 4.3 Medium (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N) |
| EPSS Score | 0.36% (29.53rd Percentile) |
| Primary Impact | Unauthorized enumeration and download of tenant firmware artifacts |
| Patched Version | Eclipse hawkBit 1.0.4 |
The application does not perform an authorization check when an actor attempts to access a resource or perform an action. In Eclipse hawkBit, the DDI controller fails to verify that a requested software module or firmware artifact is actively assigned to or installed on the requesting target device.
CVE-2026-62284 (GHSA-5w5g-j6hw-6p8f) is a code injection and server-side request forgery vulnerability in the console-proxy component of the OSAC Operator. The RemoteConfigResolver parses Kubernetes Secrets containing kubeconfig files via clientcmd.RESTConfigFromKubeConfig without sanitizing execution-related fields. An attacker with RBAC permissions to create or modify labeled Secrets in monitored namespaces can supply a malicious exec credential plugin, resulting in arbitrary command execution within the console-proxy pod.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.
GHSA-fmc8-p6q7-75cc (associated with CVE-2026-48755) is a critical argument injection vulnerability in Canonical LXD (github.com/canonical/lxd). The vulnerability occurs during instance and storage volume backup operations when processing the user-supplied compression_algorithm configuration parameter. While LXD validates the primary executable token against an allowlist of supported compression binaries, it fails to sanitize or restrict subsequent tokens parsed via shellquote.Split. These additional arguments are passed directly to exec.Command. An authenticated attacker with privileges to trigger backups can inject command-line flags for utilities like zstd to read staged files from a container filesystem and write them to arbitrary paths on the underlying host filesystem, such as /etc/cron.d/, achieving root-level arbitrary code execution on the host.