Skip to content

Commit acf951b

Browse files
1 parent cc57e38 commit acf951b

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-77xj-rrh3-wx3v",
4+
"modified": "2026-03-04T20:44:35Z",
5+
"published": "2026-03-04T20:44:35Z",
6+
"aliases": [],
7+
"summary": "`time_calibrator` was removed from crates.io due to malicious code",
8+
"details": "It was reported `time_calibrator` contained malicious code, that would try to upload `.env` files to a server.\n\nThe malicious crate had only 1 version published at 2026-02-28 and no evidence of actual usage. The crate was removed from crates.io and the user account was locked. There were no crates depending on this crate on crates.io.\n\nRust security response working group thanks Gabriel Silva for finding and reporting this, and thanks to Emily Albini for co-ordinating with the crates.io and infra-admin teams.",
9+
"severity": [],
10+
"affected": [
11+
{
12+
"package": {
13+
"ecosystem": "crates.io",
14+
"name": "time_calibrator"
15+
},
16+
"ranges": [
17+
{
18+
"type": "ECOSYSTEM",
19+
"events": [
20+
{
21+
"introduced": "0"
22+
}
23+
]
24+
}
25+
]
26+
}
27+
],
28+
"references": [
29+
{
30+
"type": "WEB",
31+
"url": "https://rustsec.org/advisories/RUSTSEC-2026-0030.html"
32+
}
33+
],
34+
"database_specific": {
35+
"cwe_ids": [],
36+
"severity": "CRITICAL",
37+
"github_reviewed": true,
38+
"github_reviewed_at": "2026-03-04T20:44:35Z",
39+
"nvd_published_at": null
40+
}
41+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-v33r-r6h2-8wr7",
4+
"modified": "2026-03-04T20:43:17Z",
5+
"published": "2026-03-04T20:43:17Z",
6+
"aliases": [
7+
"CVE-2026-28685"
8+
],
9+
"summary": "Kimai's API invoice endpoint missing customer-level access control (IDOR)",
10+
"details": "## Summary\n\n`GET /api/invoices/{id}` only checks the role-based `view_invoice` permission but does not verify the requesting user has `access` to the invoice's customer. Any user with `ROLE_TEAMLEAD` (which grants `view_invoice`) can read all invoices in the system, including those belonging to customers assigned to other teams.\n\n## Affected Code\n\n`src/API/InvoiceController.php` line 92-101:\n\n```php\n#[IsGranted('view_invoice')] // Role check only, no customer access check\n#[Route(methods: ['GET'], path: '/{id}', name: 'get_invoice', requirements: ['id' => '\\d+'])]\npublic function getAction(Invoice $invoice): Response\n{\n $view = new View($invoice, 200);\n $view->getContext()->setGroups(self::GROUPS_ENTITY);\n return $this->viewHandler->handle($view); // Returns ANY invoice by ID\n}\n```\n\nThe web controller (`src/Controller/InvoiceController.php` line 304-307) correctly checks customer access:\n\n```php\n#[IsGranted('view_invoice')]\n#[IsGranted(new Expression(\"is_granted('access', subject.getCustomer())\"), 'invoice')]\npublic function downloadAction(Invoice $invoice, ...): Response { ... }\n```\n\nThe `access` attribute in `CustomerVoter` (line 71-87) verifies team membership, but this check is entirely missing from the API endpoint.\n\n## PoC\n\nTested against Kimai v2.50.0 (Docker: `kimai/kimai2:apache`).\n\nSetup:\n- TeamA with CustomerA (\"SecretCorp\"), TeamB with CustomerB (\"BobCorp\")\n- Bob is a teamlead in TeamB only\n- An invoice exists for SecretCorp (TeamA)\n\n```bash\n# Bob (TeamB) reads SecretCorp (TeamA) invoice\ncurl -H \"Authorization: Bearer BOB_TOKEN\" http://localhost:8888/api/invoices/1\n```\n\nResponse (200 OK):\n```json\n{\n \"invoiceNumber\": \"INV-2026-001\",\n \"total\": 15000.0,\n \"currency\": \"USD\",\n \"customer\": {\"name\": \"SecretCorp\", ...}\n}\n```\n\nBob can also enumerate all invoices via `GET /api/invoices` — the list endpoint uses `setCurrentUser()` in the query but the single-item endpoint bypasses this entirely via Symfony ParamConverter.\n\n## Impact\n\nAny teamlead can read all invoices across the system regardless of team assignment. Invoice data typically contains sensitive financial information (amounts, customer details, payment terms). In multi-team deployments this breaks the intended data isolation between teams.\n\n## Suggested Fix\n\nAdd the customer access check to the API endpoint, matching the web controller:\n\n```diff\n #[IsGranted('view_invoice')]\n+#[IsGranted(new Expression(\"is_granted('access', subject.getCustomer())\"), 'invoice')]\n #[Route(methods: ['GET'], path: '/{id}', name: 'get_invoice')]\n public function getAction(Invoice $invoice): Response\n```",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "kimai/kimai"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "2.51.0"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 2.50.0"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/kimai/kimai/security/advisories/GHSA-v33r-r6h2-8wr7"
45+
},
46+
{
47+
"type": "WEB",
48+
"url": "https://github.com/kimai/kimai/commit/a0601c8cb28fed1cca19051a8272425069ab758f"
49+
},
50+
{
51+
"type": "PACKAGE",
52+
"url": "https://github.com/kimai/kimai"
53+
},
54+
{
55+
"type": "WEB",
56+
"url": "https://github.com/kimai/kimai/releases/tag/2.51.0"
57+
}
58+
],
59+
"database_specific": {
60+
"cwe_ids": [
61+
"CWE-862"
62+
],
63+
"severity": "MODERATE",
64+
"github_reviewed": true,
65+
"github_reviewed_at": "2026-03-04T20:43:17Z",
66+
"nvd_published_at": null
67+
}
68+
}

0 commit comments

Comments
 (0)