CVE-2023-44392 (published 2023-10-09T20:15Z)

Garden provides automation for Kubernetes development and testing. Prior tov ersions 0.13.17 and 0.12.65, Garden has a dependency on the cryo library, which is vulnerable to code injection due to an insecure implementation of deserialization. Garden stores serialized objects using cryo in the Kubernetes `ConfigMap` resources prefixed with `test-result` and `run-result` to cache Garden test and run results. These `ConfigMaps` are stored either in the `garden-system` namespace or the configured user namespace. When a user invokes the command `garden test` or `garden run` objects stored in the `ConfigMap` are retrieved and deserialized. This can be used by an attacker with access to the Kubernetes cluster to store malicious objects in the `ConfigMap`, which can trigger a remote code execution on the users machine when cryo deserializes the object. In order to exploit this vulnerability, an attacker must have access to the Kubernetes cluster used to deploy garden remote environments. Further, a user must actively invoke either a `garden test` or `garden run` which has previously cached results. The issue has been patched in Garden versions `0.13.17` (Bonsai) and `0.12.65` (Acorn). Only Garden versions prior to these are vulnerable. No known workarounds are available.

CVSS v3 base score: 9.0, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-94
cwe_name: Improper Control of Generation of Code ('Code Injection')
description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
extended_description: 
            When a product allows a user's input to contain code syntax, it might be possible for an attacker to craft the code in such a way that it will alter the intended control flow of the product. Such an alteration could lead to arbitrary code execution.
            Injection problems encompass a wide variety of issues -- all mitigated in very different ways. For this reason, the most effective way to discuss these weaknesses is to note the distinct features which classify them as injection weaknesses. The most important issue to note is that all injection problems share one thing in common -- i.e., they allow for the injection of control plane data into the user-controlled data plane. This means that the execution of the process may be altered by sending code in through legitimate data channels, using no other mechanism. While buffer overflows, and many other flaws, involve the use of some further issue to gain execution, injection problems need only for the data to be parsed. The most classic instantiations of this category of weakness are SQL injection and format string vulnerabilities.
         
         
cwe_id: CWE-502
cwe_name: Deserialization of Untrusted Data
description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
extended_description: 
            It is often convenient to serialize objects for communication or to save them for later use. However, deserialized data or code can often be modified without using the provided accessor functions if it does not use cryptography to protect itself. Furthermore, any cryptography would still be client-side security -- which is a dangerous security assumption.
            Data that is untrusted can not be trusted to be well-formed.
            When developers place no restrictions on "gadget chains," or series of instances and method invocations that can self-execute during the deserialization process (i.e., before the object is returned to the caller), it is sometimes possible for attackers to leverage them to perform unauthorized actions, like generating a shell.
         
         

Fix information:
repo_url: https://github.com/garden-io/garden
commit_details: repo_url: https://github.com/garden-io/garden
author: Steffen Neubauer
author_date: 2023-10-04 13:01:50+02:00
msg: chore(deps): remove cryo (#5179)
repository: repo_url: https://github.com/garden-io/garden
repo_name: garden-io/garden
description: Automation for Kubernetes development and testing. Spin up production-like environments for development, testing, and CI on demand. Use the same configuration and workflows at every step of the process. Speed up your builds and test runs via shared result caching
repo_language: TypeScript
owner: garden-io
file_changes: filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -53,7 +53,6 @@
     "cli-truncate": "^2.1.0",
     "cpy": "^8.1.2",
     "cross-spawn": "^7.0.3",
-    "cryo": "0.0.6",
     "crypto-random-string": "^3.3.1",
     "date-fns": "^2.29.3",
     "dedent": "^0.7.0",
@@ -247,8 +246,8 @@
     "md5": "^2.3.0",
     "mocha": "^10.2.0",
     "nock": "^12.0.3",
-    "nodemon": "^2.0.15",
     "node-fetch": "^2.7.0",
+    "nodemon": "^2.0.15",
     "nyc": "^15.1.0",
     "p-event": "^4.2.0",
     "peggy": "^3.0.2",

programming_language: Jupyter Notebook
filename: run-results.ts
change_type: ModificationType.MODIFY
diff: @@ -65,7 +65,9 @@ export const k8sGetRunResult: RunActionHandler<"getResult", any> = async (params
 }
 
 export function getRunResultKey(ctx: PluginContext, action: Action) {
-  const key = `${ctx.projectName}--${action.type}.${action.name}--${action.versionString()}`
+  // change the result format version if the result format changes breaking backwards-compatibility e.g. serialization format
+  const resultFormatVersion = 1
+  const key = `${ctx.projectName}--${action.type}.${action.name}--${action.versionString()}--${resultFormatVersion}`
   const hash = hasha(key, { algorithm: "sha1" })
   return `run-result--${hash.slice(0, 32)}`
 }

programming_language: TypeScript
filename: test-results.ts
change_type: ModificationType.MODIFY
diff: @@ -57,7 +57,9 @@ export const k8sGetTestResult: TestActionHandler<"getResult", any> = async (para
 }
 
 export function getTestResultKey(ctx: PluginContext, action: StoreTestResultParams["action"]) {
-  const key = `${ctx.projectName}--${action.name}--${action.versionString()}`
+  // change the result format version if the result format changes breaking backwards-compatibility e.g. serialization format
+  const resultFormatVersion = 1
+  const key = `${ctx.projectName}--${action.name}--${action.versionString()}--${resultFormatVersion}`
   const hash = hasha(key, { algorithm: "sha1" })
   return `test-result--${hash.slice(0, 32)}`
 }

programming_language: TypeScript
filename: serialization.ts
change_type: ModificationType.MODIFY
diff: @@ -7,7 +7,6 @@
  */
 
 import { mapValues } from "lodash"
-import Cryo from "cryo"
 import { writeFile } from "fs-extra"
 import { DumpOptions, dump } from "js-yaml"
 import highlight from "cli-highlight"
@@ -50,11 +49,11 @@ export async function dumpYamlMulti(yamlPath: string, objects: object[]) {
 }
 
 export function serializeObject(o: any): string {
-  return Buffer.from(Cryo.stringify(o)).toString("base64")
+  return Buffer.from(JSON.stringify(o)).toString("base64")
 }
 
 export function deserializeObject(s: string) {
-  return Cryo.parse(Buffer.from(s, "base64"))
+  return JSON.parse(Buffer.from(s, "base64").toString())
 }
 
 export function serializeValues(o: { [key: string]: any }): { [key: string]: string } {

programming_language: TypeScript