Advisories for Pypi/Lemur package

2026

Lemur: Unchecked `replaces[]` lets any user silence notifications and hijack auto-rotation for arbitrary certificates

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 …

Lemur: Sub-CA creation never checks `AuthorityPermission` on the parent authority

Repo under test: https://github.com/Netflix/lemur When ADMIN_ONLY_AUTHORITY_CREATION=False (an explicitly supported and documented configuration), POST /api/1/authorities with type=subca never verifies that the caller holds AuthorityPermission on the supplied parent authority. The parent field is resolved by AssociatedAuthoritySchema via a raw fetch_objects(Authority, data) lookup, then passed straight through service.create → mint → cryptography-issuer.create_authority, which loads options["parent"].authority_certificate.private_key and signs a brand-new intermediate CA on the caller's behalf. Any authenticated non-read-only user can therefore mint …

Lemur: SSRF protection in certificate revocation checking bypassable via HTTP redirects and DNS rebinding (incomplete fix for GHSA-54vg-pfh7-jq95)

The SSRF mitigation added for GHSA-54vg-pfh7-jq95 (_validate_revocation_url() in lemur /certificates/verify.py) can be bypassed. An operator-role user who uploads a certificate with attacker-controlled CRL/OCSP extensions can still make Lemur reach internal destinations (RFC1918, loopback, link-local 169.254.169.254) during verification.

Lemur: Server-Side Request Forgery via the ACME client following server-controlled URLs

The ACME client (used to issue certificates from Let's Encrypt / Google Public CA / private ACME CAs) connects to an acme_url, then issues requests to URLs that the ACME server returns in its directory/order/authorization/finalize responses - this is the classic ACME-client SSRF (RFC 8555 design). Lemur validates acme_url against an allowlist of public ACME directories, but only at authority creation. The authority UPDATE path (PUT /authorities/<id>) accepts a new …

Lemur: Missing authorization check on POST /certificates/<id>/export for plugins with requires_key = False

The CertificateExport handler in lemur/certificates/views.py nests its entire ownership / CertificatePermission check inside an if plugin.requires_key: branch. When the selected export plugin advertises requires_key = False, the authorization check is skipped entirely and any authenticated user can invoke plugin.export(cert.body, cert.chain, cert.private_key, options) against a certificate they do not own. The handler additionally writes a "key_view" audit-log event for every call, regardless of whether the plugin actually accessed the private key, …

Lemur: Incomplete fix for GHSA-v2wp-frmc-5q3v -- ACME authority update endpoint allows non-admin to replace `acme_url` with internal IP, bypassing allowlist

The fix for GHSA-v2wp-frmc-5q3v added _validate_acme_url() to reject acme_url values not in ACME_DIRECTORY_HOST_ALLOWLIST, but the validation is only called at authority creation time (POST). The authority update endpoint (PUT /api/1/authorities/<id>) accepts and stores arbitrary options – including a modified acme_url – without invoking the allowlist check. Any user with an authority role (granted by an admin to allow issuing certificates via that authority) can therefore overwrite the stored acme_url with …

Lemur: Authenticated low-privilege users can read plaintext destination credentials (SFTP password / private-key passphrase) via the destinations API

Lemur's destination read endpoints – GET /api/1/destinations and GET /api/1/destinations/<id> – return the full set of stored plugin option values to any authenticated user, with no authorization check and no redaction of secret-bearing options. The sibling write endpoints (POST/PUT/DELETE) are gated with @admin_permission.require(http_exception=403), but the two read handlers are protected only by login_required (inherited from AuthenticatedResource). They do not even exclude read-only users. The built-in SFTP destination plugin (sftp-destination) stores …

Lemur: Any user can revoke arbitrary certificates at the CA by uploading a duplicate record and revoking it

Repo under test: https://github.com/Netflix/lemur PUT /api/1/certificates/<id>/revoke authorizes the caller against the Lemur database row (creator == current user, or CertificatePermission over the row's roles) rather than the underlying CA-side certificate identity. Separately, POST /api/1/certificates/upload lets any user passing StrictRolePermission create a new Certificate row while freely supplying body, authority (resolved by id/name with no AuthorityPermission check) and external_id; there is no uniqueness constraint on body, serial, or external_id. An attacker …

Lemur: Crafted CRL/OCSP URLs in uploaded certificates lead to post-authentication SSRF

When verifying an uploaded certificate, lemur/certificates/verify.py extracts the CRL Distribution Point URL and the OCSP responder URL directly from the certificate's extensions and issues outbound requests to those URLs without scheme restriction or destination allow-listing. An authenticated user holding the operator role (required by StrictRolePermission on POST /certificates/upload) can craft a certificate whose extensions point at internal services - instance metadata endpoints, internal Kubernetes API servers, RFC1918 hosts, link-local addresses …

Lemur: ACME SSRF + creator-equality IDOR lead to AWS IAM/PKI compromise

Field | Value – | – Title | Lemur 1.9.0: any SSO-authenticated user achieves AWS IAM compromise and permanent PKI key access via ACME acme_url SSRF and creator-equality IDOR Component | lemur/lemur/plugins/lemur_acme/acme_handlers.py:161-201 (SSRF), lemur/lemur/certificates/views.py:734 (IDOR), lemur/lemur/auth/views.py:300-308 (SSO auto-provision) CWE | CWE-918 (SSRF) + CWE-639 (Authorization Bypass Through User-Controlled Key) + CWE-285 (Improper Authorization) Attack Prerequisite | A valid SSO session against the deployment's IdP. Lemur auto-provisions any new SSO identity …

Lemur user-update path stores plaintext passwords

lemur.users.service.update() writes a user's new password as plaintext to the users.password column. The User model wires bcrypt hashing to SQLAlchemy's before_insert event but registers no equivalent listener for before_update, and service.update() does not call user.hash_password() after assigning the new value. Every password change performed through the admin-gated PUT /api/1/users/<id> endpoint persists the user's password to the database in cleartext.

Lemur Privilege Escalation: Non-admin role members can rewrite role membership via PUT /api/1/roles/<id>

The PUT /api/1/roles/<id> handler in lemur/roles/views.py gates only on RoleMemberPermission(role_id).can(), which is satisfied for any user who is already a member of the target role. The handler then passes data["users"] and data["name"] directly to service.update(), permitting any role member to rewrite that role's membership list and name. The companion DELETE handler on the same resource is correctly gated by @admin_permission.require; the asymmetry between PUT and DELETE on identical resources indicates …

Lemur has an authorization bypass in StrictRolePermission / AuthorityCreatorPermission

StrictRolePermission and AuthorityCreatorPermission in lemur/auth/permissions.py call flask_principal.Permission.init() with zero Needs when their config flags are unset. Both flags defaulted to False in code prior to the fix, so this was the state of any Lemur install that hadn't explicitly opted in. Flask-Principal's Permission.allows() returns True whenever self.needs is empty. The .can() gate therefore passes for every authenticated identity, including the lowest-privilege role Lemur ships (read-only). A user holding only read-only …

Lemur: JWT verifier honors attacker-supplied alg, enabling ATO

Field | Value – | – Title | Lemur 1.9.0: JWT verifier trusts attacker-supplied alg from token header — defense-in-depth gap; chain-dependent ATO with secret disclosure Component | lemur/lemur/auth/service.py:130-137 CWE | CWE-347 (Improper Verification of Cryptographic Signature) Attack Prerequisite | Defense-in-depth gap on its own — no single-request exploit against PyJWT 2.x. Single-request ATO requires a separate disclosure issue that leaks LEMUR_TOKEN_SECRET, or a future migration to asymmetric signing without …

2023

Duplicate Advisory: Lemur subject to insecure random generation

Duplicate Advisory This advisory has been withdrawn because it is a duplicate of GHSA-5fqv-mpj8-h7gm. This link is maintained to preserve external references. Original Description Netflix Lemur before version 1.3.2 used insufficiently random values when generating default credentials. The insufficiently random values may allow an attacker to guess the credentials and gain access to resources managed by Lemur.

2022