CWE-639
AllowedAuthorization Bypass Through User-Controlled Key
Abstraction: Base · Status: Incomplete
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
4215 vulnerabilities reference this CWE, most recent first.
GHSA-C9HW-VRGH-HH3M
Vulnerability from github – Published: 2026-07-09 06:31 – Updated: 2026-07-09 06:31The Divi Form Builder plugin for WordPress is vulnerable to Missing Authorization in versions up to, and including, 5.1.8. This is due to the update_user() function accepting a user ID parameter from form submissions without verifying that the authenticated user has permission to edit that specific user account, and the handle_register_submission() function only checking if any user is logged in rather than validating permissions for the target user. This makes it possible for authenticated attackers, with subscriber-level access and above, to change the email address and password of any user account, including administrators, resulting in complete account takeover.
{
"affected": [],
"aliases": [
"CVE-2026-5523"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-09T06:16:21Z",
"severity": "HIGH"
},
"details": "The Divi Form Builder plugin for WordPress is vulnerable to Missing Authorization in versions up to, and including, 5.1.8. This is due to the update_user() function accepting a user ID parameter from form submissions without verifying that the authenticated user has permission to edit that specific user account, and the handle_register_submission() function only checking if any user is logged in rather than validating permissions for the target user. This makes it possible for authenticated attackers, with subscriber-level access and above, to change the email address and password of any user account, including administrators, resulting in complete account takeover.",
"id": "GHSA-c9hw-vrgh-hh3m",
"modified": "2026-07-09T06:31:59Z",
"published": "2026-07-09T06:31:59Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-5523"
},
{
"type": "WEB",
"url": "https://diviengine.com/divi-form-builder-changelog"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/cb158acc-69d7-4a7d-b356-7de1f6b37019?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-C9M9-282W-83CP
Vulnerability from github – Published: 2026-09-15 03:30 – Updated: 2026-09-15 03:30Soft Serve versions 0.7.1 through 0.11.6 fail to scope Git LFS lock queries by repository, allowing authenticated users to read lock metadata from repositories they cannot access. Attackers with write access to any repository can enumerate lock IDs globally to recover locked file paths, usernames, and lock timestamps from private repositories.
{
"affected": [],
"aliases": [
"CVE-2026-91773"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-15T02:16:50Z",
"severity": "MODERATE"
},
"details": "Soft Serve versions 0.7.1 through 0.11.6 fail to scope Git LFS lock queries by repository, allowing authenticated users to read lock metadata from repositories they cannot access. Attackers with write access to any repository can enumerate lock IDs globally to recover locked file paths, usernames, and lock timestamps from private repositories.",
"id": "GHSA-c9m9-282w-83cp",
"modified": "2026-09-15T03:30:30Z",
"published": "2026-09-15T03:30:30Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/charmbracelet/soft-serve/security/advisories/GHSA-xqg9-4q65-m2wf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-91773"
},
{
"type": "WEB",
"url": "https://github.com/charmbracelet/soft-serve/commit/e34914699128c937afad167d43ccb5310e48b319"
},
{
"type": "WEB",
"url": "https://github.com/charmbracelet/soft-serve"
},
{
"type": "WEB",
"url": "https://github.com/charmbracelet/soft-serve/blob/v0.11.6/pkg/store/database/lfs.go#L115-L124"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/soft-serve-0.7.1-through-0.11.6-information-disclosure-via-lfs-locks"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-CC7F-7QRJ-R4V2
Vulnerability from github – Published: 2024-09-06 15:32 – Updated: 2026-06-03 18:33Exposure of Sensitive Information to an Unauthorized Actor vulnerability in Ariva Computer Accord ORS allows Retrieve Embedded Sensitive Data.This issue affects Accord ORS: before 7.3.2.1.
{
"affected": [],
"aliases": [
"CVE-2024-1744"
],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-09-06T13:15:03Z",
"severity": "CRITICAL"
},
"details": "Exposure of Sensitive Information to an Unauthorized Actor vulnerability in Ariva Computer Accord ORS allows Retrieve Embedded Sensitive Data.This issue affects Accord ORS: before 7.3.2.1.",
"id": "GHSA-cc7f-7qrj-r4v2",
"modified": "2026-06-03T18:33:05Z",
"published": "2024-09-06T15:32:58Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-1744"
},
{
"type": "WEB",
"url": "https://siberguvenlik.gov.tr/guvenlik-bildirimleri/detay/tr-24-1408"
},
{
"type": "WEB",
"url": "https://www.usom.gov.tr/bildirim/tr-24-1408"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-CC7G-VFW3-M4MR
Vulnerability from github – Published: 2026-02-06 03:30 – Updated: 2026-02-06 03:30The Timeline Block – Beautiful Timeline Builder for WordPress (Vertical & Horizontal Timelines) plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.3.3 via the tlgb_shortcode() function due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Author-level access and above, to disclose private timeline content via the id attribute supplied to the 'timeline_block' shortcode.
{
"affected": [],
"aliases": [
"CVE-2026-1228"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-02-06T03:15:48Z",
"severity": "MODERATE"
},
"details": "The Timeline Block \u2013 Beautiful Timeline Builder for WordPress (Vertical \u0026 Horizontal Timelines) plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.3.3 via the tlgb_shortcode() function due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Author-level access and above, to disclose private timeline content via the id attribute supplied to the \u0027timeline_block\u0027 shortcode.",
"id": "GHSA-cc7g-vfw3-m4mr",
"modified": "2026-02-06T03:30:19Z",
"published": "2026-02-06T03:30:19Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1228"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset/3446078/timeline-block-block"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/cecebfd0-c2af-4150-8793-299cdbeaa7b9?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-CCC2-WRMM-MGWP
Vulnerability from github – Published: 2026-06-11 12:32 – Updated: 2026-06-11 12:32Cerebrate before version 1.37 allowed the id primary key field to be supplied through request input during CRUD edit operations and certain custom entity patching flows. In affected entities that did not explicitly mark id as inaccessible, an authenticated attacker could submit a crafted edit request containing the id of another record, causing the save operation to update that unrelated record instead of the record identified by the route parameter. The issue affected several entity types inheriting permissive mass-assignment defaults, including User, Role, UserSetting, LocalTool, PermissionLimitation, and EnumerationCollection. Since UserSettings edit functionality was reachable by any authenticated user, exploitation could allow unauthorized modification of records within the same entity type, with impact depending on the affected endpoint and writable fields. Cerebrate 1.37 fixes this by stripping id from request input after marshalling callbacks and by globally marking id as inaccessible in the base AppModel entity.
The discovery of those potential vulnerabilities are inherited from initial finding from Jeroen Pinoy additional support from AI-Assisted Optus 4.8 (the commit wrongly assign Claude Fable 5 as the model switched) and coordinated by Andras Iklody.
{
"affected": [],
"aliases": [
"CVE-2026-53911"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-11T10:16:21Z",
"severity": "MODERATE"
},
"details": "Cerebrate before version 1.37 allowed the id primary key field to be supplied through request input during CRUD edit operations and certain custom entity patching flows. In affected entities that did not explicitly mark id as inaccessible, an authenticated attacker could submit a crafted edit request containing the id of another record, causing the save operation to update that unrelated record instead of the record identified by the route parameter. The issue affected several entity types inheriting permissive mass-assignment defaults, including User, Role, UserSetting, LocalTool, PermissionLimitation, and EnumerationCollection. Since UserSettings edit functionality was reachable by any authenticated user, exploitation could allow unauthorized modification of records within the same entity type, with impact depending on the affected endpoint and writable fields. Cerebrate 1.37 fixes this by stripping id from request input after marshalling callbacks and by globally marking id as inaccessible in the base AppModel entity.\n\nThe discovery of those potential vulnerabilities are inherited from initial finding from Jeroen Pinoy additional support from AI-Assisted Optus 4.8 (the commit wrongly assign Claude Fable 5 as the model switched) and coordinated by Andras Iklody.",
"id": "GHSA-ccc2-wrmm-mgwp",
"modified": "2026-06-11T12:32:44Z",
"published": "2026-06-11T12:32:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53911"
},
{
"type": "WEB",
"url": "https://github.com/cerebrate-project/cerebrate/commit/b3c8f951b0634f05691339512ef06cc261afecaf"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-CCG5-9C8W-XH6V
Vulnerability from github – Published: 2026-09-09 18:01 – Updated: 2026-09-09 18:01Summary
ModelView.sort_query() uses the attacker-controlled sortBy list-view query parameter without checking it against the configured column_sortable_list allow-list. The value is resolved with getattr(model, ...) and fed into relationship joins and order_by(), so a request can sort by any column of the model — including ones hidden from column_list — and, via a dotted path, by columns of related models. Because row order then reflects the value of an unexposed column, this is an information-exposure ordering oracle.
Root cause
column_sortable_list is consulted only in the list template to decide which header links to render; the server never enforces it, so removing a column from the UI does not prevent sorting by it.
Exploitation
A single request leaks the relative ordering of an unexposed column; the asc↔desc reversal confirms rows are ordered by the secret's actual value. Pairing sortBy with searchable/filterable columns and pagination can narrow the oracle toward specific values, though value recovery is conditional on having a filterable target column.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "sqladmin"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.27.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54529"
],
"database_specific": {
"cwe_ids": [
"CWE-20",
"CWE-200",
"CWE-248",
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-09T18:01:56Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\n`ModelView.sort_query()` uses the attacker-controlled `sortBy` list-view query parameter without checking it against the configured `column_sortable_list` allow-list. The value is resolved with `getattr(model, ...)` and fed into relationship joins and `order_by()`, so a request can sort by **any** column of the model \u2014 including ones hidden from `column_list` \u2014 and, via a dotted path, by columns of related models. Because row order then reflects the value of an unexposed column, this is an information-exposure **ordering oracle**.\n\n## Root cause\n\n`column_sortable_list` is consulted only in the list template to decide which header links to render; the server never enforces it, so removing a column from the UI does not prevent sorting by it.\n\n## Exploitation\n\nA single request leaks the relative ordering of an unexposed column; the `asc`\u2194`desc` reversal confirms rows are ordered by the secret\u0027s actual value. Pairing `sortBy` with searchable/filterable columns and pagination can narrow the oracle toward specific values, though value recovery is conditional on having a filterable target column.",
"id": "GHSA-ccg5-9c8w-xh6v",
"modified": "2026-09-09T18:01:56Z",
"published": "2026-09-09T18:01:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/smithyhq/sqladmin/security/advisories/GHSA-ccg5-9c8w-xh6v"
},
{
"type": "PACKAGE",
"url": "https://github.com/smithyhq/sqladmin"
},
{
"type": "WEB",
"url": "https://github.com/smithyhq/sqladmin/releases/tag/0.27.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "SQLAdmin: Unvalidated sortBy parameter in `ModelView` bypasses `column_sortable_list`"
}
GHSA-CCGQ-FX7H-2V4C
Vulnerability from github – Published: 2026-09-15 18:32 – Updated: 2026-09-15 18:32Vikunja before 2.6.0 fails to validate that user-supplied project_view_id in task-position requests belongs to the task's project. Authenticated attackers can insert task position rows into arbitrary other tenant project views via POST or PUT task-position endpoints.
{
"affected": [],
"aliases": [
"CVE-2026-91984"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-15T16:17:55Z",
"severity": "MODERATE"
},
"details": "Vikunja before 2.6.0 fails to validate that user-supplied project_view_id in task-position requests belongs to the task\u0027s project. Authenticated attackers can insert task position rows into arbitrary other tenant project views via POST or PUT task-position endpoints.",
"id": "GHSA-ccgq-fx7h-2v4c",
"modified": "2026-09-15T18:32:30Z",
"published": "2026-09-15T18:32:30Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/go-vikunja/vikunja/security/advisories/GHSA-w39f-h553-h2mx"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-91984"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/vikunja-before-2.6.0-broken-object-level-authorization-via-task-position"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-CCGV-2JPF-98M2
Vulnerability from github – Published: 2026-08-27 18:32 – Updated: 2026-08-27 18:32Affected versions of Flowintel contain an insecure direct object reference / broken object-level authorization issue across numerous task endpoints.
The routes generally received both a case identifier and a task identifier, but previously they did not enforce that the task actually belonged to the supplied case. As a result, an authenticated user with editor-level access to one case could potentially substitute the ID of a task from another case and invoke operations against that foreign task.
The patch introduces task_case_bound_required, which loads both objects and returns 404 unless the task belongs to the requested case. This protection is applied to edit, delete, note, assignment, status, file, export, MISP-linking, subtask, external-reference, and other task-related endpoints.
The fix also adds explicit checks that a requested note_id belongs to the current task before returning or exporting it, closing related cross-object access paths.
Version impacted =>3.3.0
{
"affected": [],
"aliases": [
"CVE-2026-81817"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-27T17:21:05Z",
"severity": "HIGH"
},
"details": "Affected versions of Flowintel contain an insecure direct object reference / broken object-level authorization issue across numerous task endpoints.\n\n\nThe routes generally received both a case identifier and a task identifier, but previously they did not enforce that the task actually belonged to the supplied case. As a result, an authenticated user with editor-level access to one case could potentially substitute the ID of a task from another case and invoke operations against that foreign task.\n\n\nThe patch introduces task_case_bound_required, which loads both objects and returns 404 unless the task belongs to the requested case. This protection is applied to edit, delete, note, assignment, status, file, export, MISP-linking, subtask, external-reference, and other task-related endpoints.\n\nThe fix also adds explicit checks that a requested note_id belongs to the current task before returning or exporting it, closing related cross-object access paths.\n\nVersion impacted =\u003e3.3.0",
"id": "GHSA-ccgv-2jpf-98m2",
"modified": "2026-08-27T18:32:30Z",
"published": "2026-08-27T18:32:30Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-81817"
},
{
"type": "WEB",
"url": "https://github.com/flowintel/flowintel/commit/10676eec7f1286d7ee0769546c772c5cb9c1c72b.patch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-CCHP-3RQ6-69WJ
Vulnerability from github – Published: 2024-06-21 09:30 – Updated: 2025-03-24 21:45An issue was discovered in the events2 (aka Events 2) extension before 8.3.8 and 9.x before 9.0.6 for TYPO3. Missing access checks in the management plugin lead to an insecure direct object reference (IDOR) vulnerability with the potential to activate or delete various events for unauthenticated users.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "jweiland/events2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "8.3.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "jweiland/events2"
},
"ranges": [
{
"events": [
{
"introduced": "9.0.0"
},
{
"fixed": "9.0.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-38874"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-693"
],
"github_reviewed": true,
"github_reviewed_at": "2024-06-21T15:07:37Z",
"nvd_published_at": "2024-06-21T07:15:10Z",
"severity": "MODERATE"
},
"details": "An issue was discovered in the events2 (aka Events 2) extension before 8.3.8 and 9.x before 9.0.6 for TYPO3. Missing access checks in the management plugin lead to an insecure direct object reference (IDOR) vulnerability with the potential to activate or delete various events for unauthenticated users.",
"id": "GHSA-cchp-3rq6-69wj",
"modified": "2025-03-24T21:45:07Z",
"published": "2024-06-21T09:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-38874"
},
{
"type": "WEB",
"url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/jweiland/events2/CVE-2024-38874.yaml"
},
{
"type": "PACKAGE",
"url": "https://github.com/jweiland-net/events2"
},
{
"type": "WEB",
"url": "https://typo3.org/security/advisory/typo3-ext-sa-2024-003"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "events2 TYPO3 extension insecure direct object reference (IDOR) vulnerability"
}
GHSA-CFH6-PV5C-38JV
Vulnerability from github – Published: 2026-08-18 20:51 – Updated: 2026-08-18 20:51Summary
Repo under test: https://github.com/Netflix/lemur
The certificate create and upload endpoints accept a replaces[] (alias replacements) array that is resolved to live Certificate ORM objects with no ownership or CertificatePermission check on the referenced certificates. The SQLAlchemy Certificate.replaces append listener then immediately sets victim.notify = False and populates victim.replaced. From that point the victim certificate is excluded from auto-reissue, its expiration notifications are silenced, and the periodic certificate_rotate Celery task deploys the attacker's certificate (endpoint.certificate.replaced[0]) onto every endpoint serving the victim certificate.
Any authenticated non-read-only user can therefore silently substitute their own certificate onto production load balancers and Kubernetes secrets they hold no role on, while suppressing the legitimate certificate's lifecycle automation.
Affected route
POST /api/1/certificates
POST /api/1/certificates/upload
PUT /api/1/certificates/<id>
Affected code
lemur/certificates/schemas.py:402—replaces = fields.Nested(AssociatedCertificateSchema, missing=[], many=True)accepted on create/upload/editlemur/schemas.py:152—AssociatedCertificateSchemaresolves any certificate by id/name viafetch_objects(Certificate, data)with no permission checklemur/certificates/views.py:651— onlyStrictRolePermission().can()gates/certificates/upload; no check ondata['replaces']lemur/certificates/models.py:506—@event.listens_for(Certificate.replaces, 'append')setsvalue.notify = Falseon the victimlemur/certificates/service.py:277—get_all_pending_reissue()filtersnot_(Certificate.replaced.any()), excluding the victimlemur/certificates/cli.py:347—request_rotation(endpoint, endpoint.certificate.replaced[0], message, commit)deploys the attacker certlemur/common/celery.py:638— periodiccertificate_rotatetask runscli_certificate.rotate(..., commit=True)lemur/deployment/service.py:17—endpoint.source.plugin.update_endpoint(endpoint, new_cert)pushes to ELB/CloudFront/ACM/K8s
Impact
An authenticated insider or holder of a stolen low-privilege token can, without holding any role on a target certificate:
- Upload a self-signed or attacker-minted certificate listing arbitrary high-value production certificate IDs in
replaces. - Immediately disable expiration notifications and auto-reissue for those production certificates.
- On the next scheduled
certificate_rotateCelery run, have the attacker's certificate pushed to every endpoint (AWS ELB/CloudFront/ACM, Kubernetes, SFTP, etc.) currently serving the victim certificate, while the legitimate certificate is detached.
Minimum impact is fleet-wide TLS denial of service equivalent to mass revocation. Where internal clients trust the substituted chain (or combined with the sub-CA finding LEMUR-BUG-07), it escalates to TLS interception. This directly violates the invariant that a user may only modify or revoke a certificate if they are its owner, a member of an owning role, or an administrator.
Root cause
AssociatedCertificateSchema.get_object calls fetch_objects(Certificate, data) and returns the ORM rows verbatim. No caller on the create/upload/edit path iterates the resolved replaces list to enforce CertificatePermission before the model assigns them, and the Certificate.replaces append event listener mutates the victim row (notify = False) as a side effect of ORM collection assignment. The direct revoke endpoint does enforce CertificatePermission, but this replaces path achieves an equivalent or worse outcome while bypassing it entirely.
Validated evidence
Static trace, confirmed by code inspection (validation status: CONFIRMED):
replacesis accepted inCertificateInputSchema/CertificateUploadInputSchemaand resolved viafetch_objects(Certificate, ...)with no per-object authorization.grep -n CertificatePermission lemur/certificates/views.pyshows the check is applied toPUT/DELETE/revoke/exportpaths but never to thereplacespayload ofPOST /certificatesorPOST /certificates/upload.- The Celery
certificate_rotatetask andcli.rotate()consumeEndpoint.replaced.any()unconditionally and deployreplaced[0]withcommit=True.
Proof of concept / reproducer
Status: reconstructed from source report (static control-flow trace; not executed against a live CA).
Preconditions: attacker is an authenticated Lemur user holding any role other than read-only (default StrictRolePermission config). <VICTIM_CERT_ID> is any certificate id readable via GET /api/1/certificates.
# 1. Upload an attacker-controlled cert that "replaces" the victim
curl -sS -X POST "<TARGET_BASE_URL>/api/1/certificates/upload" \
-H "Authorization: Bearer <AUTH_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "attacker-replacement",
"owner": "attacker@example.com",
"body": "-----BEGIN CERTIFICATE-----\n<ATTACKER_CERT_PEM>\n-----END CERTIFICATE-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\n<ATTACKER_KEY_PEM>\n-----END PRIVATE KEY-----",
"replaces": [{"id": <VICTIM_CERT_ID>}]
}'
# 2. Observe victim.notify is now false and victim is queued for rotation
curl -sS "<TARGET_BASE_URL>/api/1/certificates/<VICTIM_CERT_ID>" \
-H "Authorization: Bearer <AUTH_TOKEN>" | jq '.notify, .replaced'
# 3. On the next certificate_rotate Celery beat tick, the attacker cert is
# deployed to every endpoint that was serving <VICTIM_CERT_ID>.
Static-trace validation command from the source report:
grep -n 'replaces' lemur/certificates/schemas.py lemur/certificates/views.py lemur/schemas.py \
&& grep -n 'CertificatePermission' lemur/certificates/views.py
Source artifact: audit/harnesses/public-repo-threat-model-harness/results/netflix-lemur-100run-mythos-20260627T051129Z/findings.jsonl (run_083, finding cluster lemur-replaces-unauth, 7/100 runs).
Suggested fix
Before persisting replaces/replacements on certificate create, upload, and edit, iterate each referenced certificate and enforce the same CertificatePermission(owner_role, cert.roles) check used by the revoke endpoint (views.py:1677-1685); reject with 403 if the caller is not creator/owner/role-member/admin for any target. Additionally, move the value.notify = False side effect out of the SQLAlchemy append listener so an authorization failure cannot leave a victim certificate partially mutated, and emit an audit_log entry whenever a certificate is marked as replaced.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.9.2"
},
"package": {
"ecosystem": "PyPI",
"name": "lemur"
},
"ranges": [
{
"events": [
{
"introduced": "0.5.0"
},
{
"fixed": "1.9.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-71308"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-18T20:51:33Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nRepo under test: https://github.com/Netflix/lemur\n\nThe certificate create and upload endpoints accept a `replaces[]` (alias `replacements`) array that is resolved to live `Certificate` ORM objects with no ownership or `CertificatePermission` check on the referenced certificates. The SQLAlchemy `Certificate.replaces` append listener then immediately sets `victim.notify = False` and populates `victim.replaced`. From that point the victim certificate is excluded from auto-reissue, its expiration notifications are silenced, and the periodic `certificate_rotate` Celery task deploys the attacker\u0027s certificate (`endpoint.certificate.replaced[0]`) onto every endpoint serving the victim certificate.\n\nAny authenticated non-read-only user can therefore silently substitute their own certificate onto production load balancers and Kubernetes secrets they hold no role on, while suppressing the legitimate certificate\u0027s lifecycle automation.\n\n## Affected route\n\n`POST /api/1/certificates`\n`POST /api/1/certificates/upload`\n`PUT /api/1/certificates/\u003cid\u003e`\n\n## Affected code\n\n- [`lemur/certificates/schemas.py:402`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/schemas.py#L402) \u2014 `replaces = fields.Nested(AssociatedCertificateSchema, missing=[], many=True)` accepted on create/upload/edit\n- [`lemur/schemas.py:152`](https://github.com/Netflix/lemur/blob/main/lemur/schemas.py#L152) \u2014 `AssociatedCertificateSchema` resolves any certificate by id/name via `fetch_objects(Certificate, data)` with no permission check\n- [`lemur/certificates/views.py:651`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/views.py#L651) \u2014 only `StrictRolePermission().can()` gates `/certificates/upload`; no check on `data[\u0027replaces\u0027]`\n- [`lemur/certificates/models.py:506`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/models.py#L506) \u2014 `@event.listens_for(Certificate.replaces, \u0027append\u0027)` sets `value.notify = False` on the victim\n- [`lemur/certificates/service.py:277`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/service.py#L277) \u2014 `get_all_pending_reissue()` filters `not_(Certificate.replaced.any())`, excluding the victim\n- [`lemur/certificates/cli.py:347`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/cli.py#L347) \u2014 `request_rotation(endpoint, endpoint.certificate.replaced[0], message, commit)` deploys the attacker cert\n- [`lemur/common/celery.py:638`](https://github.com/Netflix/lemur/blob/main/lemur/common/celery.py#L638) \u2014 periodic `certificate_rotate` task runs `cli_certificate.rotate(..., commit=True)`\n- [`lemur/deployment/service.py:17`](https://github.com/Netflix/lemur/blob/main/lemur/deployment/service.py#L17) \u2014 `endpoint.source.plugin.update_endpoint(endpoint, new_cert)` pushes to ELB/CloudFront/ACM/K8s\n\n## Impact\n\nAn authenticated insider or holder of a stolen low-privilege token can, without holding any role on a target certificate:\n\n1. Upload a self-signed or attacker-minted certificate listing arbitrary high-value production certificate IDs in `replaces`.\n2. Immediately disable expiration notifications and auto-reissue for those production certificates.\n3. On the next scheduled `certificate_rotate` Celery run, have the attacker\u0027s certificate pushed to every endpoint (AWS ELB/CloudFront/ACM, Kubernetes, SFTP, etc.) currently serving the victim certificate, while the legitimate certificate is detached.\n\nMinimum impact is fleet-wide TLS denial of service equivalent to mass revocation. Where internal clients trust the substituted chain (or combined with the sub-CA finding LEMUR-BUG-07), it escalates to TLS interception. This directly violates the invariant that a user may only modify or revoke a certificate if they are its owner, a member of an owning role, or an administrator.\n\n## Root cause\n\n`AssociatedCertificateSchema.get_object` calls `fetch_objects(Certificate, data)` and returns the ORM rows verbatim. No caller on the create/upload/edit path iterates the resolved `replaces` list to enforce `CertificatePermission` before the model assigns them, and the `Certificate.replaces` append event listener mutates the victim row (`notify = False`) as a side effect of ORM collection assignment. The direct revoke endpoint *does* enforce `CertificatePermission`, but this `replaces` path achieves an equivalent or worse outcome while bypassing it entirely.\n\n## Validated evidence\n\nStatic trace, confirmed by code inspection (validation status: `CONFIRMED`):\n\n- `replaces` is accepted in `CertificateInputSchema` / `CertificateUploadInputSchema` and resolved via `fetch_objects(Certificate, ...)` with no per-object authorization.\n- `grep -n CertificatePermission lemur/certificates/views.py` shows the check is applied to `PUT`/`DELETE`/`revoke`/`export` paths but never to the `replaces` payload of `POST /certificates` or `POST /certificates/upload`.\n- The Celery `certificate_rotate` task and `cli.rotate()` consume `Endpoint.replaced.any()` unconditionally and deploy `replaced[0]` with `commit=True`.\n\n## Proof of concept / reproducer\n\nStatus: reconstructed from source report (static control-flow trace; not executed against a live CA).\n\nPreconditions: attacker is an authenticated Lemur user holding any role other than `read-only` (default `StrictRolePermission` config). `\u003cVICTIM_CERT_ID\u003e` is any certificate id readable via `GET /api/1/certificates`.\n\n```bash\n# 1. Upload an attacker-controlled cert that \"replaces\" the victim\ncurl -sS -X POST \"\u003cTARGET_BASE_URL\u003e/api/1/certificates/upload\" \\\n -H \"Authorization: Bearer \u003cAUTH_TOKEN\u003e\" \\\n -H \"Content-Type: application/json\" \\\n -d \u0027{\n \"name\": \"attacker-replacement\",\n \"owner\": \"attacker@example.com\",\n \"body\": \"-----BEGIN CERTIFICATE-----\\n\u003cATTACKER_CERT_PEM\u003e\\n-----END CERTIFICATE-----\",\n \"privateKey\": \"-----BEGIN PRIVATE KEY-----\\n\u003cATTACKER_KEY_PEM\u003e\\n-----END PRIVATE KEY-----\",\n \"replaces\": [{\"id\": \u003cVICTIM_CERT_ID\u003e}]\n }\u0027\n\n# 2. Observe victim.notify is now false and victim is queued for rotation\ncurl -sS \"\u003cTARGET_BASE_URL\u003e/api/1/certificates/\u003cVICTIM_CERT_ID\u003e\" \\\n -H \"Authorization: Bearer \u003cAUTH_TOKEN\u003e\" | jq \u0027.notify, .replaced\u0027\n\n# 3. On the next certificate_rotate Celery beat tick, the attacker cert is\n# deployed to every endpoint that was serving \u003cVICTIM_CERT_ID\u003e.\n```\n\nStatic-trace validation command from the source report:\n\n```bash\ngrep -n \u0027replaces\u0027 lemur/certificates/schemas.py lemur/certificates/views.py lemur/schemas.py \\\n \u0026\u0026 grep -n \u0027CertificatePermission\u0027 lemur/certificates/views.py\n```\n\nSource artifact: `audit/harnesses/public-repo-threat-model-harness/results/netflix-lemur-100run-mythos-20260627T051129Z/findings.jsonl` (run_083, finding cluster `lemur-replaces-unauth`, 7/100 runs).\n\n## Suggested fix\n\nBefore persisting `replaces`/`replacements` on certificate create, upload, and edit, iterate each referenced certificate and enforce the same `CertificatePermission(owner_role, cert.roles)` check used by the revoke endpoint ([`views.py:1677-1685`](https://github.com/Netflix/lemur/blob/main/lemur/certificates/views.py#L1677)); reject with 403 if the caller is not creator/owner/role-member/admin for any target. Additionally, move the `value.notify = False` side effect out of the SQLAlchemy append listener so an authorization failure cannot leave a victim certificate partially mutated, and emit an `audit_log` entry whenever a certificate is marked as replaced.",
"id": "GHSA-cfh6-pv5c-38jv",
"modified": "2026-08-18T20:51:33Z",
"published": "2026-08-18T20:51:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Netflix/lemur/security/advisories/GHSA-cfh6-pv5c-38jv"
},
{
"type": "WEB",
"url": "https://github.com/Netflix/lemur/commit/286874535160952143b0afe2d356642669f9d4c6"
},
{
"type": "PACKAGE",
"url": "https://github.com/Netflix/lemur"
},
{
"type": "WEB",
"url": "https://github.com/Netflix/lemur/releases/tag/v1.9.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Lemur: Unchecked `replaces[]` lets any user silence notifications and hijack auto-rotation for arbitrary certificates"
}
Mitigation
For each and every data access, ensure that the user has sufficient privilege to access the record that is being requested.
Mitigation
Make sure that the key that is used in the lookup of a specific user's record is not controllable externally by the user or that any tampering can be detected.
Mitigation
Use encryption in order to make it more difficult to guess other legitimate values of the key or associate a digital signature with the key so that the server can verify that there has been no tampering.
No CAPEC attack patterns related to this CWE.