VYPR
Medium severity4.9NVD Advisory· Published Apr 3, 2026· Updated Apr 21, 2026

CVE-2025-68152

CVE-2025-68152

Description

Juju is an open source application orchestration engine that enables any application operation on any infrastructure at any scale through special operators called ‘charms’. From versions 2.9 to before 2.9.56 and 3.6 to before 3.6.19, it is possible that a compromised workload machine under a Juju controller can read any log file for any entity in any model at any level. This issue has been patched in versions 2.9.56 and 3.6.19.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/juju/jujuGo
< 0.0.0-20250623030540-c91a1f4046950.0.0-20250623030540-c91a1f404695

Affected products

1

Patches

2
22cdcf6b54c2

fix: ensure users uploading tools need admin permission on the model

https://github.com/juju/jujuwallyworldJun 18, 2025via ghsa
2 files changed · +35 13
  • apiserver/apiserver.go+12 11 modified
    @@ -708,11 +708,12 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     	healthHandler := srv.monitoredHandler(http.HandlerFunc(srv.healthHandler), "health")
     	logStreamHandler := srv.monitoredHandler(newLogStreamEndpointHandler(httpCtxt), "logstream")
     	embeddedCLIHandler := srv.monitoredHandler(newEmbeddedCLIHandler(httpCtxt), "commands")
    +	controllerAdminAuthorizer := controllerAdminAuthorizer{
    +		controllerTag: systemState.ControllerTag(),
    +	}
     	var debuglogAuth httpcontext.CompositeAuthorizer = []authentication.Authorizer{
     		tagKindAuthorizer{names.MachineTagKind, names.ControllerAgentTagKind},
    -		controllerAdminAuthorizer{
    -			controllerTag: systemState.ControllerTag(),
    -		},
    +		controllerAdminAuthorizer,
     		modelPermissionAuthorizer{
     			perm: permission.ReadAccess,
     		},
    @@ -757,9 +758,7 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     		GetHandler:  modelCharmsHandler.ServeGet,
     	}, "charms")
     	var modelCharmsUploadAuthorizer httpcontext.CompositeAuthorizer = []authentication.Authorizer{
    -		controllerAdminAuthorizer{
    -			controllerTag: systemState.ControllerTag(),
    -		},
    +		controllerAdminAuthorizer,
     		modelPermissionAuthorizer{
     			perm: permission.WriteAccess,
     		},
    @@ -779,7 +778,12 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     		ctxt:          httpCtxt,
     		stateAuthFunc: httpCtxt.stateForRequestAuthenticatedUser,
     	}, "tools")
    -	modelToolsUploadAuthorizer := tagKindAuthorizer{names.UserTagKind}
    +	var modelToolsUploadAuthorizer httpcontext.CompositeAuthorizer = []authentication.Authorizer{
    +		controllerAdminAuthorizer,
    +		modelPermissionAuthorizer{
    +			perm: permission.AdminAccess,
    +		},
    +	}
     	modelToolsDownloadHandler := srv.monitoredHandler(newToolsDownloadHandler(httpCtxt), "tools")
     	resourcesHandler := srv.monitoredHandler(&ResourcesHandler{
     		StateAuthFunc: func(req *http.Request, tagKinds ...string) (ResourcesBackend, state.PoolHelper, names.Tag,
    @@ -826,9 +830,6 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     		},
     	}, "units")
     
    -	controllerAdminAuthorizer := controllerAdminAuthorizer{
    -		controllerTag: systemState.ControllerTag(),
    -	}
     	migrateCharmsHandler := &charmsHandler{
     		ctxt:          httpCtxt,
     		dataDir:       srv.dataDir,
    @@ -983,7 +984,7 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     	}, {
     		pattern:    "/tools",
     		handler:    modelToolsUploadHandler,
    -		authorizer: modelToolsUploadAuthorizer,
    +		authorizer: controllerAdminAuthorizer,
     	}, {
     		pattern:         "/tools/:version",
     		handler:         modelToolsDownloadHandler,
    
  • apiserver/tools_test.go+23 2 modified
    @@ -24,6 +24,7 @@ import (
     	gc "gopkg.in/check.v1"
     
     	apitesting "github.com/juju/juju/apiserver/testing"
    +	"github.com/juju/juju/core/permission"
     	"github.com/juju/juju/environs"
     	"github.com/juju/juju/environs/simplestreams"
     	"github.com/juju/juju/environs/storage"
    @@ -177,7 +178,7 @@ func (s *toolsSuite) TestRequiresPOST(c *gc.C) {
     	s.assertJSONErrorResponse(c, resp, http.StatusMethodNotAllowed, `unsupported method: "PUT"`)
     }
     
    -func (s *toolsSuite) TestAuthRequiresUser(c *gc.C) {
    +func (s *toolsSuite) TestAuthRejectsNonsUser(c *gc.C) {
     	// Add a machine and try to login.
     	machine, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobHostUnits)
     	c.Assert(err, jc.ErrorIsNil)
    @@ -197,14 +198,34 @@ func (s *toolsSuite) TestAuthRequiresUser(c *gc.C) {
     	})
     	s.assertPlainErrorResponse(
     		c, resp, http.StatusForbidden,
    -		"authorization failed: tag kind machine not valid",
    +		"authorization failed: permission denied",
     	)
     
     	// Now try a user login.
     	resp = s.sendHTTPRequest(c, apitesting.HTTPRequestParams{Method: "POST", URL: s.toolsURI("")})
     	s.assertJSONErrorResponse(c, resp, http.StatusBadRequest, "expected binaryVersion argument")
     }
     
    +func (s *toolsSuite) TestAuthRejectsUserWithoutPermission(c *gc.C) {
    +	u := s.Factory.MakeUser(c, &factory.UserParams{
    +		Name:     "oryx",
    +		Password: "gardener",
    +		Access:   permission.WriteAccess,
    +	})
    +
    +	resp := apitesting.SendHTTPRequest(c, apitesting.HTTPRequestParams{
    +		Tag:      u.Tag().String(),
    +		Password: "gardener",
    +		Method:   "POST",
    +		URL:      s.toolsURI(""),
    +		Nonce:    "fake_nonce",
    +	})
    +	s.assertPlainErrorResponse(
    +		c, resp, http.StatusForbidden,
    +		"authorization failed: permission denied",
    +	)
    +}
    +
     func (s *toolsSuite) TestUploadRequiresVersion(c *gc.C) {
     	resp := s.sendHTTPRequest(c, apitesting.HTTPRequestParams{Method: "POST", URL: s.toolsURI("")})
     	s.assertJSONErrorResponse(c, resp, http.StatusBadRequest, "expected binaryVersion argument")
    
c91a1f404695

fix: ensure that users wanting to use debug-log via the /log

https://github.com/juju/jujuwallyworldJun 13, 2025via ghsa
3 files changed · +41 28
  • apiserver/apiserver.go+11 6 modified
    @@ -48,6 +48,7 @@ import (
     	coredatabase "github.com/juju/juju/core/database"
     	"github.com/juju/juju/core/lease"
     	"github.com/juju/juju/core/multiwatcher"
    +	"github.com/juju/juju/core/permission"
     	"github.com/juju/juju/core/presence"
     	"github.com/juju/juju/core/resources"
     	"github.com/juju/juju/internal/worker/syslogger"
    @@ -707,15 +708,19 @@ func (srv *Server) endpoints() ([]apihttp.Endpoint, error) {
     	healthHandler := srv.monitoredHandler(http.HandlerFunc(srv.healthHandler), "health")
     	logStreamHandler := srv.monitoredHandler(newLogStreamEndpointHandler(httpCtxt), "logstream")
     	embeddedCLIHandler := srv.monitoredHandler(newEmbeddedCLIHandler(httpCtxt), "commands")
    +	var debuglogAuth httpcontext.CompositeAuthorizer = []authentication.Authorizer{
    +		tagKindAuthorizer{names.MachineTagKind, names.ControllerAgentTagKind},
    +		controllerAdminAuthorizer{
    +			controllerTag: systemState.ControllerTag(),
    +		},
    +		modelPermissionAuthorizer{
    +			perm: permission.ReadAccess,
    +		},
    +	}
     	debugLogHandler := srv.monitoredHandler(newDebugLogDBHandler(
     		httpCtxt,
     		httpAuthenticator,
    -		tagKindAuthorizer{
    -			names.MachineTagKind,
    -			names.ControllerAgentTagKind,
    -			names.UserTagKind,
    -			names.ApplicationTagKind,
    -		},
    +		debuglogAuth,
     	), "log")
     	pubsubHandler := srv.monitoredHandler(newPubSubHandler(httpCtxt, srv.shared.centralHub), "pubsub")
     	logSinkHandler := logsink.NewHTTPHandler(
    
  • apiserver/debuglog_db_test.go+18 2 modified
    @@ -14,6 +14,7 @@ import (
     
     	apitesting "github.com/juju/juju/apiserver/testing"
     	"github.com/juju/juju/apiserver/websocket/websockettest"
    +	"github.com/juju/juju/core/permission"
     	"github.com/juju/juju/rpc/params"
     	"github.com/juju/juju/testing/factory"
     )
    @@ -59,16 +60,17 @@ func (s *debugLogDBSuite) TestUnitLoginsRejected(c *gc.C) {
     	conn, _, err := s.dialWebsocketInternal(c, nil, header)
     	c.Assert(err, jc.ErrorIsNil)
     
    -	websockettest.AssertJSONError(c, conn, "authorization failed: tag kind unit not valid")
    +	websockettest.AssertJSONError(c, conn, "authorization failed: permission denied")
     	websockettest.AssertWebsocketClosed(c, conn)
     }
     
     var noResultsPlease = url.Values{"maxLines": {"0"}, "noTail": {"true"}}
     
    -func (s *debugLogDBSuite) TestUserLoginsAccepted(c *gc.C) {
    +func (s *debugLogDBSuite) TestUserLoginAccepted(c *gc.C) {
     	u := s.Factory.MakeUser(c, &factory.UserParams{
     		Name:     "oryx",
     		Password: "gardener",
    +		Access:   permission.ReadAccess,
     	})
     	header := jujuhttp.BasicAuthHeader(u.Tag().String(), "gardener")
     	conn, _, err := s.dialWebsocketInternal(c, noResultsPlease, header)
    @@ -80,6 +82,20 @@ func (s *debugLogDBSuite) TestUserLoginsAccepted(c *gc.C) {
     	c.Assert(result.Error, gc.IsNil)
     }
     
    +func (s *debugLogDBSuite) TestUserLoginRejected(c *gc.C) {
    +	u := s.Factory.MakeUser(c, &factory.UserParams{
    +		Name:        "oryx",
    +		Password:    "gardener",
    +		NoModelUser: true,
    +	})
    +	header := jujuhttp.BasicAuthHeader(u.Tag().String(), "gardener")
    +	conn, _, err := s.dialWebsocketInternal(c, noResultsPlease, header)
    +	c.Assert(err, jc.ErrorIsNil)
    +
    +	websockettest.AssertJSONError(c, conn, "authorization failed: permission denied")
    +	websockettest.AssertWebsocketClosed(c, conn)
    +}
    +
     func (s *debugLogDBSuite) TestMachineLoginsAccepted(c *gc.C) {
     	m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{
     		Nonce: "foo-nonce",
    
  • go.sum+12 20 modified
    @@ -18,8 +18,7 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW
     cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
     cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
     cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
    -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
    -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
    +cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
     cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
     cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
     cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
    @@ -952,21 +951,17 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
     go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
     go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
     go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
    -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
    -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
    +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
     go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
    -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
    -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
    +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
     go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
    -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
    -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
    +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
     go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
    -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
    -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
    -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
    -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
    -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
    -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
    +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
    +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
    +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
    +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
    +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
     go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
     go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
     go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
    @@ -1294,8 +1289,7 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR
     google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
     google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
     google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
    -google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
    -google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
    +google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
     google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
     google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
     google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
    @@ -1349,8 +1343,7 @@ google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRx
     google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
     google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
     google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
    -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
    -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
    +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
     google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
     google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
     google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
    @@ -1372,8 +1365,7 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
     google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
     google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
     google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
    -google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
    -google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
    +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
     google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
     google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
     google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.