CVE-2023-47090
Description
NATS nats-server before 2.9.23 and 2.10.x before 2.10.2 has an authentication bypass. An implicit $G user in an authorization block can sometimes be used for unauthenticated access, even when the intention of the configuration was for each user to have an account. The earliest affected version is 2.2.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
NATS nats-server authentication bypass via implicit $G user when $SYS account is defined, allowing unauthenticated access; fixed in 2.9.23/2.10.2.
Vulnerability
Overview
CVE-2023-47090 is an authentication bypass in NATS nats-server versions before 2.9.23 and 2.10.x before 2.10.2, affecting configurations that define an $SYS system account alongside a top-level authorization block. When such a configuration is active, the server's parsing logic incorrectly creates an implicit $G (global) user that bypasses the intended authentication requirement. This allows unauthenticated connections to be accepted and mapped to the $G user, even when the operator explicitly intended every user to authenticate with credentials [1][2].
Exploitation
Conditions
To exploit this vulnerability, an attacker only needs network access to the NATS server's port (default 4222). No prior authentication is required. The attack is triggered by simply connecting without providing any credentials. The server, misidentifying the connection as matching the implicit $G user, grants access. This behavior was observed when an $SYS account was defined in the accounts block, which altered the server's handling of the top-level authorization block [1].
Impact
An unauthenticated attacker who successfully exploits this flaw gains the permissions assigned to the default $G user. Depending on the server's configuration, this may allow publishing or subscribing to sensitive subjects, accessing JetStream streams, or interacting with system accounts. The impact ranges from unauthorized data access to potential denial-of-service if the attacker can exhaust resources via the misassigned user [1].
Mitigation
The issue is fixed in nats-server versions 2.9.23 and 2.10.2. The fix adds an internal authBlockDefined flag in the Options struct to properly track whether a top-level authorization block was explicitly defined, preventing the creation of an unintended $G user [2][3]. Users unable to upgrade should review their configuration to avoid mixing top-level authorization blocks with $SYS account definitions, or consider using explicit no_auth_user settings with restricted permissions [1]. The official release notes confirm the patch is included in v2.10.2 [4].
- Issue with denying unauthenticated connections · nats-io nats-server · Discussion #4535
- [FIXED] Do not bypass authorization blocks when turning on $SYS account access by derekcollison · Pull Request #4605 · nats-io/nats-server
- [FIXED] Do not bypass authorization blocks when turning on $SYS accou… · nats-io/nats-server@fa5b7af
- Release Release v2.10.2 · nats-io/nats-server
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/nats-io/nats-server/v2Go | >= 2.2.0, < 2.9.23 | 2.9.23 |
github.com/nats-io/nats-server/v2Go | >= 2.10.0, < 2.10.2 | 2.10.2 |
Affected products
4- NATS/nats-serverdescription
- osv-coords3 versions
< 0.1.1-r5+ 2 more
- (no CPE)range: < 0.1.1-r5
- (no CPE)range: < 0.1.1-r5
- (no CPE)range: >= 2.2.0, < 2.9.23
Patches
1fa5b7afcb64e[FIXED] Do not bypass authorization blocks when turning on $SYS account access (#4605)
5 files changed · +45 −11
server/opts.go+4 −1 modified@@ -395,6 +395,9 @@ type Options struct { // OCSP Cache config enables next-gen cache for OCSP features OCSPCacheConfig *OCSPResponseCacheConfig + + // Used to mark that we had a top level authorization block. + authBlockDefined bool } // WebsocketOpts are options for websocket @@ -885,7 +888,7 @@ func (o *Options) processConfigFileLine(k string, v interface{}, errors *[]error *errors = append(*errors, err) return } - + o.authBlockDefined = true o.Username = auth.user o.Password = auth.pass o.Authorization = auth.token
server/opts_test.go+10 −7 modified@@ -120,6 +120,7 @@ func TestConfigFile(t *testing.T) { LameDuckDuration: 4 * time.Minute, ConnectErrorReports: 86400, ReconnectErrorReports: 5, + authBlockDefined: true, } opts, err := ProcessConfigFile("./configs/test.conf") @@ -132,13 +133,14 @@ func TestConfigFile(t *testing.T) { func TestTLSConfigFile(t *testing.T) { golden := &Options{ - ConfigFile: "./configs/tls.conf", - Host: "127.0.0.1", - Port: 4443, - Username: "derek", - Password: "foo", - AuthTimeout: 1.0, - TLSTimeout: 2.0, + ConfigFile: "./configs/tls.conf", + Host: "127.0.0.1", + Port: 4443, + Username: "derek", + Password: "foo", + AuthTimeout: 1.0, + TLSTimeout: 2.0, + authBlockDefined: true, } opts, err := ProcessConfigFile("./configs/tls.conf") if err != nil { @@ -283,6 +285,7 @@ func TestMergeOverrides(t *testing.T) { LameDuckDuration: 4 * time.Minute, ConnectErrorReports: 86400, ReconnectErrorReports: 5, + authBlockDefined: true, } fopts, err := ProcessConfigFile("./configs/test.conf") if err != nil {
server/routes_test.go+2 −1 modified@@ -105,7 +105,8 @@ func TestRouteConfig(t *testing.T) { NoAdvertise: true, ConnectRetries: 2, }, - PidFile: "/tmp/nats-server/nats_cluster_test.pid", + PidFile: "/tmp/nats-server/nats_cluster_test.pid", + authBlockDefined: true, } // Setup URLs
server/server.go+2 −2 modified@@ -1239,8 +1239,8 @@ func (s *Server) configureAccounts(reloading bool) (map[string]struct{}, error) // If we have defined a system account here check to see if its just us and the $G account. // We would do this to add user/pass to the system account. If this is the case add in // no-auth-user for $G. - // Only do this if non-operator mode. - if len(opts.TrustedOperators) == 0 && numAccounts == 2 && opts.NoAuthUser == _EMPTY_ { + // Only do this if non-operator mode and we did not have an authorization block defined. + if len(opts.TrustedOperators) == 0 && numAccounts == 2 && opts.NoAuthUser == _EMPTY_ && !opts.authBlockDefined { // If we come here from config reload, let's not recreate the fake user name otherwise // it will cause currently clients to be disconnected. uname := s.sysAccOnlyNoAuthUser
server/server_test.go+27 −0 modified@@ -19,6 +19,7 @@ import ( "context" "crypto/tls" "encoding/json" + "errors" "flag" "fmt" "io" @@ -2080,3 +2081,29 @@ func TestServerRateLimitLogging(t *testing.T) { checkLog(c1, c2) } + +// https://github.com/nats-io/nats-server/discussions/4535 +func TestServerAuthBlockAndSysAccounts(t *testing.T) { + conf := createConfFile(t, []byte(` + listen: 127.0.0.1:-1 + server_name: s-test + authorization { + users = [ { user: "u", password: "pass"} ] + } + accounts { + $SYS: { users: [ { user: admin, password: pwd } ] } + } + `)) + + s, _ := RunServerWithConfig(conf) + defer s.Shutdown() + + // This should work of course. + nc, err := nats.Connect(s.ClientURL(), nats.UserInfo("u", "pass")) + require_NoError(t, err) + defer nc.Close() + + // This should not. + _, err = nats.Connect(s.ClientURL()) + require_Error(t, err, nats.ErrAuthorization, errors.New("nats: Authorization Violation")) +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-fr2g-9hjm-wr23ghsaADVISORY
- www.openwall.com/lists/oss-security/2023/10/30/1mitremailing-list
- advisories.nats.io/CVE/secnote-2023-01.txtghsaWEB
- github.com/nats-io/nats-server/commit/fa5b7afcb64e7e887e49afdd032358802b5c4478ghsaWEB
- github.com/nats-io/nats-server/pull/4605ghsaWEB
- github.com/nats-io/nats-server/releases/tag/v2.10.2ghsaWEB
- github.com/nats-io/nats-server/releases/tag/v2.9.23ghsaWEB
- github.com/nats-io/nats-server/security/advisories/GHSA-fr2g-9hjm-wr23ghsaWEB
- www.openwall.com/lists/oss-security/2023/10/13/2mitre
News mentions
0No linked articles in our index yet.