Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs · Issue #13306 · apache/cloudstack · GitHub
Open Graph Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs · Issue #13306 · apache/cloudstack
X Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs · Issue #13306 · apache/cloudstack
Description: Advisory Details Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs Description: Apache CloudStack's certificate management subsystem is vulnerable to plaintext credential exposure (CWE-532). When provisioning or updatin...
Open Graph Description: Advisory Details Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs Description: Apache CloudStack's certificate management subsystem is vulnerable to plaintext credential exposure...
X Description: Advisory Details Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs Description: Apache CloudStack's certificate management subsystem is vulnerable to plaintext credential expo...
Opengraph URL: https://github.com/apache/cloudstack/issues/13306
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs","articleBody":"### Advisory Details\n\n**Title**: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs\n\n**Description**:\nApache CloudStack's certificate management subsystem is vulnerable to plaintext credential exposure (CWE-532). When provisioning or updating TLS certificates for remote host agents, the management server executes command strings over SSH via the utility class `com.cloud.utils.ssh.SSHCmdHelper`. To sanitize these command lines before logging them at debug visibility, the helper employs an ad-hoc and fragile string splitting strategy (`cmd.split(KeyStoreUtils.KS_FILENAME)[0]`) using `cloud.jks` as the split token. Because the password argument in the `keystore-cert-import` script is formatted *before* the `cloud.jks` filename argument, the password remains in the 0-indexed split array element and is logged in plaintext to the server's debug output log, exposing KVM keystore passwords to unauthorized actors.\n\n### Summary\n\nAn unpatched credential leakage vulnerability in the remote SSH command execution helper utility allows any unprivileged user or system-level attacker with read access to the management server's log files to obtain plaintext host keystore administration credentials, compromising the secure communication channel between the management server and remote agent host nodes.\n\n### Details\n\nDuring agent certificate指配 (provisioning) operations, the method `CAManagerImpl.provisionCertificateViaSsh()` generates high-entropy random passwords for host keystores using `PasswordGenerator.generateRandomPassword(16)` and constructs shell execution parameters. \n\nIn `CAManagerImpl.java`, two utility commands are executed via SSH:\n1. **Keystore Setup:** `keystore-setup \u003cPROPERTIES\u003e cloud.jks \u003cPASSWORD\u003e \u003cVALIDITY\u003e \u003cCSR\u003e`\n2. **Keystore Import:** `keystore-cert-import \u003cPROPERTIES\u003e \u003cPASSWORD\u003e cloud.jks \u003cSSH_MODE\u003e ...`\n\nIn `SSHCmdHelper.java`, command strings are written to the management server logs at a debug level:\n\n```java\n// SSHCmdHelper.java\npublic static SSHCmdResult sshExecuteCmdOneShot(com.trilead.ssh2.Connection sshConnection, String cmd) throws SshException {\n LOGGER.debug(\"Executing cmd: \" + cmd.split(KeyStoreUtils.KS_FILENAME)[0]);\n```\n\nHere, `KeyStoreUtils.KS_FILENAME` is `\"cloud.jks\"`.\n\nBecause the `keystorePassword` is formatted **before** `KeyStoreUtils.KS_FILENAME` (`cloud.jks`) in the import script context, the ad-hoc truncation logic fails completely. When `cmd.split(KeyStoreUtils.KS_FILENAME)[0]` is evaluated, the resulting segment contains the plaintext password in full, which is subsequently written to the management server's logs.\n\n### PoC\n\n#### Prerequisites\n- Python 3.x is installed in the testing environment.\n- CloudStack Management Server is running (or verified academically via simulated split tests).\n\n#### Reproduction Steps\n\n1. Download the docker-compose deployment file from: [docker-compose.yml](https://gist.github.com/YLChen-007/e15ace077e3a2a0e79da3d3692857d64)\n2. Download the defect verification integration test script from: [verification_test_Issue-cloudstack-12025.py](https://gist.github.com/YLChen-007/1dea89676d623b864d609496a02ea8aa)\n3. Download the scientific control group test script from: [control-masked_output.py](https://gist.github.com/YLChen-007/d2ea48bd17f34650c7a51eb9fab2c4ba)\n4. Execute the verification test to observe academic defect validation:\n ```bash\n python3 verification_test_Issue-cloudstack-12025.py\n ```\n5. Execute the control group test to verify normal security truncation versus the bypass layout:\n ```bash\n python3 control-masked_output.py\n ```\n\n### Log of Evidence\n\n```text\n[*] Running Issue-cloudstack-12025 Sensitive Credentials Exposure in SSHCmdHelper Integration Test...\n[*] Attempting to dispatch provisionCertificate command...\n[-] Connection failed: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /client/api?hostid=00000000-0000-0000-0000-000000000000\u0026forced=true\u0026command=provisionCertificate\u0026apiKey=ADMIN_API_KEY_PLACEHOLDER\u0026response=json\u0026signature=ezVtz4qJfkTm9IVe0igZ8bbsVKY%3D (Caused by NewConnectionError(\"HTTPConnection(host='localhost', port=8080): Failed to establish a new connection: [Errno 111] Connection refused\"))\n[INCONCLUSIVE] CloudStack Management Server is offline.\n[*] Academic verification: com.cloud.utils.ssh.SSHCmdHelper is confirmed vulnerable to credential leak via SSH execute.\n[*] Vulnerability Details:\n In SSHCmdHelper.java:\n - Line 167: LOGGER.debug(\"Executing cmd: \" + cmd.split(KeyStoreUtils.KS_FILENAME)[0]);\n - Line 230: LOGGER.debug(\"SSH command: \" + cmd.split(KeyStoreUtils.KS_FILENAME)[0] + ...) ;\n - The ad-hoc sanitization splits only by KeyStoreUtils.KS_FILENAME ('cloud.jks'), leaving positional passwords entirely unsanitized if they appear before it in the command string.\n - For example, in CAManagerImpl.java, keystore-cert-import has the password argument positioned BEFORE cloud.jks:\n sudo keystore-cert-import \u003cPROPERTIES\u003e \u003cPASSWORD\u003e cloud.jks \u003cSSH_MODE\u003e ...\n This results in 'cmd.split(KeyStoreUtils.KS_FILENAME)[0]' containing '\u003cPASSWORD\u003e' in plaintext, which is directly logged to cloudstack management logs.\n[DEFECT CONFIRMED] Plaintext passwords leaked in SSHCmdHelper logs due to inadequate split-based sanitization.\n\n[*] Running Issue-cloudstack-12025 Sensitive Credentials Exposure - Control Test (Scientific Control Group)...\n\n--- [Control Group Observation] ---\nOriginal command: sudo /usr/share/cloudstack-common/scripts/util/keystore-setup /etc/cloudstack/agent/agent.properties /etc/cloudstack/agent/cloud.jks SUPER-SECRET-PASSWORD-12345 365 /etc/cloudstack/agent/cloud.csr\nLogged command: sudo /usr/share/cloudstack-common/scripts/util/keystore-setup /etc/cloudstack/agent/agent.properties /etc/cloudstack/agent/\nPassword leaked? No (Masked/Truncated)\n\n--- [Experiment Group Observation] ---\nOriginal command: sudo /usr/share/cloudstack-common/scripts/util/keystore-cert-import /etc/cloudstack/agent/agent.properties SUPER-SECRET-PASSWORD-12345 /etc/cloudstack/agent/cloud.jks ssh /etc/cloudstack/agent/cloud.crt\nLogged command: sudo /usr/share/cloudstack-common/scripts/util/keystore-cert-import /etc/cloudstack/agent/agent.properties SUPER-SECRET-PASSWORD-12345 /etc/cloudstack/agent/\nPassword leaked? Yes\n\n--- [Comparison \u0026 Verification] ---\n[SUCCESS] Control group test confirms the security mechanism (split-based truncation) functions correctly\n under normal conditions (keystore-setup where password is after cloud.jks).\n The vulnerability is specifically triggered when the password is placed before cloud.jks\n (keystore-cert-import), which completely bypasses the split-based truncation.\n```\n\n### Impact\n\n- **Vulnerability Category:** Information Exposure through Log Files (CWE-532).\n- **Scope of Exposure:** Active administratively generated keystore passwords.\n- **Affected System Assets:** Complete control plane security between the Management Server and remote hypervisor hosts. A local user with read permission to logs (or an external attacker exploiting a separate file disclosure flaw) can hijack host keystores or perform Man-in-the-Middle (MITM) hijacking of agent communication.\n\n### Affected products\n\n- **Ecosystem**: maven\n- **Package name**: org.apache.cloudstack:cloudstack\n- **Affected versions**: \u003c= 4.22.1.0\n- **Patched versions**: \u003cNone\u003e\n\n### Severity\n\n- **Severity**: Medium\n- **Vector string**: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N\n\n### Weaknesses\n\n- **CWE**: CWE-532: Insertion of Sensitive Information into Log File\n\n### Occurrences\n\n| Permalink | Description |\n| :--- | :--- |\n| [utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L166-L168](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L166-L168) | The `split`-based log truncation in `sshExecuteCmdOneShot()` that prints commands with credentials situated before the `cloud.jks` delimiter. |\n| [utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L228-L232](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L228-L232) | Plaintext credentials printed in the error session logging branch of `sshExecuteCmdOneShot()`. |\n| [server/src/main/java/org/apache/cloudstack/ca/CAManagerImpl.java#L276-L295](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/server/src/main/java/org/apache/cloudstack/ca/CAManagerImpl.java#L276-L295) | Formats remote `keystore-cert-import` commands placing the active `keystorePassword` positional parameter *before* the `KS_FILENAME` (`cloud.jks`) delimiter. |","author":{"url":"https://github.com/YLChen-007","@type":"Person","name":"YLChen-007"},"datePublished":"2026-06-01T07:12:51.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/13306/cloudstack/issues/13306"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:94b76033-0851-6092-a6c5-d712a6eb98ad |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8374:7A367:32394A:49B71D:6A4E03E7 |
| html-safe-nonce | f91abd4eeab867255d005205aa5e27783290138c9b4f0260050ec9fce7e1d3e5 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4Mzc0OjdBMzY3OjMyMzk0QTo0OUI3MUQ6NkE0RTAzRTciLCJ2aXNpdG9yX2lkIjoiMjIxNTM3NTAyOTkyNjYzNTI3IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 425ed8b334f912c3cbe5c89e9f4ad722d8d1ec8bb647c355b484013564a36360 |
| hovercard-subject-tag | issue:4561095747 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/apache/cloudstack/13306/issue_layout |
| twitter:image | https://opengraph.githubassets.com/b8cf0f86ccd48df29d8c620e1ec27eaf4ce55b92bf43b58e6aa32019eb6c1d57/apache/cloudstack/issues/13306 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/b8cf0f86ccd48df29d8c620e1ec27eaf4ce55b92bf43b58e6aa32019eb6c1d57/apache/cloudstack/issues/13306 |
| og:image:alt | Advisory Details Title: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs Description: Apache CloudStack's certificate management subsystem is vulnerable to plaintext credential exposure... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | YLChen-007 |
| hostname | github.com |
| expected-hostname | github.com |
| None | df0492960db29b4938cb72070351d6b1d0c6c0767b27ceb8394bbf4fcc0223c6 |
| turbo-cache-control | no-preview |
| go-import | github.com/apache/cloudstack git https://github.com/apache/cloudstack.git |
| octolytics-dimension-user_id | 47359 |
| octolytics-dimension-user_login | apache |
| octolytics-dimension-repository_id | 9759448 |
| octolytics-dimension-repository_nwo | apache/cloudstack |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 9759448 |
| octolytics-dimension-repository_network_root_nwo | apache/cloudstack |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 52bde38e24398476f8eb1e0760c81346c6a00812 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width