# MySolem API — Security Critique Assessment based on black-box reverse engineering of `https://qualif.mysolem.com`. --- ## Critical ### 1. `/modules/search` leaks the entire platform's device database `POST /modules/search` with an empty query (`"query": {}`) returned **4,607 modules** belonging to all users on the platform. Confirmed exposed fields: `name`, `serialNumber`, `macAddress`, `softwareVersion`, `seenAt` (last-seen timestamp), `batteryAlarm`, `uuid`, `type`, and `createdAt`. Any authenticated user can enumerate every device on the platform. This is a broken object-level authorization (BOLA / IDOR) vulnerability — the endpoint enforces authentication but not ownership scoping. **Impact**: full device inventory of all platform customers — device names, serial numbers, MAC addresses, firmware versions, and last-seen timestamps across all tenants. --- ### 2. `POST /users/search` exposes full user records including password hashes and account takeover tokens `POST /users/search` accepts an arbitrary MongoDB-style query with no ownership enforcement. Querying by any known user ID returns the complete user document, including: - Email address and full name - **Hashed password** (`password` field — 64-character hex string, consistent with unsalted SHA-256; notably not bcrypt which is Sails.js's default — warrants further analysis) - **Active password reset token** (`resetPasswordToken`) — can be used directly to take over the account without knowing the current password - **APNs and FCM push notification tokens** — allows sending arbitrary push notifications to the user's devices - Address fields, notification preferences, and app version history User IDs are trivially obtained from finding #1: every module document in the `/modules/search` dump contains the owning user's ID in its relational fields. **Proof of concept**: querying `{"query": {"id": "641c3250efed32199bed0166"}}` returned the full record for `jdheilly@solem.fr` including password hash, reset token, and 11 push tokens across iOS and Android. **Impact**: complete account takeover of any platform user via the exposed reset token, plus credential exposure (unsalted SHA-256 hashes are trivially crackable). Push token exposure enables notification spam or phishing. This is the most severe finding in this assessment. --- ### 3. `POST /outputs/search` and `POST /programs/search` expose full platform watering configuration Both search endpoints accept an empty MongoDB query with no ownership enforcement: - `POST /outputs/search` with `{"query": {}}` returned **12,034 outputs** (valve/station definitions) across all tenants, including names, flow rates, and module associations. - `POST /programs/search` with `{"query": {}}` returned **6,073 irrigation programs** across all tenants, including full schedules, station durations, start times, water-budget percentages, and weekday patterns. **Impact**: complete read access to every customer's watering configuration. Combined with finding #4 (device control), this gives an attacker enough information to silently modify or disrupt any installation on the platform. --- ### 4. `GET /remote/module/configuration` exposes device internals for any module The endpoint accepts any `moduleId` without ownership verification. Probing a foreign active module (`67697cc9673ef4bfbb4fdbbc`) returned full device configuration including: - WiFi SSID and all MAC addresses (WiFi, Bluetooth, Ethernet) - Firmware, hardware, and BLE versions - Connected network domain and IoT subdomain - Uptime counter and reset count - Active link states (WiFi, Bluetooth, modem) **Impact**: network topology and credential-adjacent data (WiFi SSID + MAC) for any online device on the platform, without owning it. --- ### 5. No authorization check on `/remote/input/getComputedSensorData` The sensor telemetry endpoint accepts any `inputId`. If an attacker enumerates input IDs (trivially derived from the module search above — they are sequential MongoDB ObjectIds), they can pull historical sensor data for any device on the platform without owning it. **Impact**: silent exfiltration of long-term environmental data (soil moisture trends, rain events, watering schedules) for any customer site. --- ### 7. `POST /module/sendManualModuleCommand` — no apparent ownership check The control endpoint takes a `moduleSerialNumber`, not a session-scoped module ID. Serial numbers are visible in the `/modules/search` dump. It is likely (not confirmed) that a valid session can send commands to modules owned by other users. **Impact**: if confirmed, any authenticated user could start or stop irrigation on any device on the platform — including commercial agricultural installations. --- ## High ### 8. Google Maps API key hard-coded in HTML The key `AIzaSyDh8fCC9vTEuN9eKewxgqWXGP9ENb5an1c` is embedded in every page load with no referrer restriction visible. It can be extracted and abused for Maps API billing fraud against the platform owner. --- ### 9. Session cookie has no observed expiry enforcement beyond 7 days Sails.js default session TTL. There is no `SameSite` attribute confirmed in the `Set-Cookie` header, which means the cookie is sent on cross-site navigated requests — making CSRF possible for state-changing endpoints despite the lack of a CSRF token check (both conditions compound each other). A `SameSite=Lax` or `SameSite=Strict` attribute would mitigate this without requiring a token. --- ### 10. No rate limiting observed on `/login` The login endpoint accepted repeated requests without delay, lockout, or CAPTCHA. Credential stuffing and brute-force attacks are uninhibited. --- ### 11. MongoDB ObjectIds as primary keys are sequentially guessable MongoDB ObjectIds encode a timestamp + machine ID + process ID + counter. They are not random. An attacker who knows one valid ID can narrow the search space for adjacent resources created around the same time. Combined with findings #1–2, this accelerates enumeration significantly. --- ## Medium ### 12. CORS is misconfigured (blank `Access-Control-Allow-Origin`) The server returns `Access-Control-Allow-Origin: ` (empty string) rather than omitting the header or setting a specific origin. This is a misconfiguration — browsers treat it as invalid, but it signals the header is being generated dynamically and may be inconsistently applied across routes. --- ### 13. No `Content-Security-Policy` header The React frontend loads without a CSP. If an XSS vulnerability exists anywhere in the app, the attacker has full access to the DOM and cookie-less session (cookies are `HttpOnly`, but XSS can still make authenticated API calls). --- ### 14. Verbose server fingerprinting `X-Powered-By: Sails ` is returned on every response. Attackers can immediately target known Sails.js CVEs without fingerprinting effort. This header should be removed. --- ### 15. Module serial numbers and MAC addresses exposed in bulk The `/modules/search` dump includes full `serialNumber`, `uuid`, `macAddress`, and `manufacturerType` for every device. These are used as authentication tokens in some IoT protocols (LoRa device EUIs, BLE MAC-based pairing). Bulk exposure reduces the bar for physical-layer attacks. --- ## Low / Informational ### 16. Qualification environment uses real production data The `qualif.mysolem.com` environment appears to share the same database as production (or a live mirror), given that real device GPS coordinates, real customer addresses, and live telemetry timestamps are visible. Qualification/staging environments should use anonymized or synthetic data. --- ### 17. Input IDs discoverable via HTML scraping Input IDs are embedded as `data-input-id` attributes in the module detail page. This is not a vulnerability on its own, but combined with #1 (module enumeration) and #2 (unrestricted telemetry), it completes the chain without requiring any guessing. --- ## Summary table | # | Finding | Confirmed | Severity | OWASP / CWE | |---|---|---|---|---| | 1 | `/modules/search` — 4,607 devices platform-wide | Yes | Critical | API1:2023 BOLA | | 2 | `/users/search` — password hashes, reset tokens, push tokens | Yes | Critical | API1:2023 BOLA / CWE-312 | | 3 | `/outputs/search` + `/programs/search` — 12K outputs, 6K programs | Yes | Critical | API1:2023 BOLA | | 4 | `/remote/module/configuration` — WiFi/MAC/firmware for any device | Yes | Critical | API1:2023 BOLA | | 5 | Sensor telemetry readable for any input ID | Likely | Critical | API1:2023 BOLA | | 6 | Sensor history readable for any module ID | Likely | High | API1:2023 BOLA | | 7 | Device control likely has no ownership check | Unconfirmed | Critical | API1:2023 BOLA | | 8 | Google Maps API key in HTML, no restriction | Yes | High | CWE-312 | | 9 | Session cookie missing `SameSite` attribute | Yes | High | CWE-352 CSRF | | 10 | No login rate limiting | Yes | High | CWE-307 | | 11 | Sequential ObjectIds accelerate enumeration | Yes | High | CWE-330 | | 12 | Blank CORS header (misconfigured) | Yes | Medium | CWE-942 | | 13 | No Content-Security-Policy | Yes | Medium | CWE-1021 | | 14 | `X-Powered-By` header leaks framework | Yes | Low | CWE-200 | | 15 | MAC/serial bulk exposure | Yes | Medium | CWE-200 | | 16 | Staging uses real data | Yes | Medium | — | | 17 | Input IDs in HTML source | Yes | Info | — | --- ## Responsible disclosure note These findings were discovered through authorized testing of an account owned by the researcher. The critical BOLA issues (#1–7) should be reported to the MySolem security team before any public disclosure, as they affect all platform customers.