CVE-2024-29032 (published 2024-03-20T21:15Z)

Qiskit IBM Runtime is an environment that streamlines quantum computations and provides optimal implementations of the Qiskit quantum computing SDK. Starting in version 0.1.0 and prior to version 0.21.2, deserializing json data using `qiskit_ibm_runtime.RuntimeDecoder` can lead to arbitrary code execution given a correctly formatted input string. Version 0.21.2 contains a fix for this issue.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/Qiskit/qiskit-ibm-runtime
commit_details: repo_url: https://github.com/Qiskit/qiskit-ibm-runtime
author: Jessie Yu
author_date: 2024-03-18 10:41:11-04:00
msg: Merge pull request from GHSA-x4x5-jv3x-9c7m

* restrict import path

* add test
repository: repo_url: https://github.com/Qiskit/qiskit-ibm-runtime
repo_name: Qiskit/qiskit-ibm-runtime
description: IBM Client for Qiskit Runtime
repo_language: Python
owner: Qiskit
file_changes: filename: json.py
change_type: ModificationType.MODIFY
diff: @@ -373,7 +373,9 @@ class RuntimeDecoder(json.JSONDecoder):
                 # to deserialize load qpy circuit and return first instruction object in that circuit.
                 circuit = _decode_and_deserialize(obj_val, load)[0]
                 return circuit.data[0][0]
-            if obj_type == "settings":
+            if obj_type == "settings" and obj["__module__"].startswith(
+                "qiskit.quantum_info.operators"
+            ):
                 return _deserialize_from_settings(
                     mod_name=obj["__module__"],
                     class_name=obj["__class__"],

programming_language: Python
filename: test_data_serialization.py
change_type: ModificationType.MODIFY
diff: @@ -27,7 +27,7 @@ from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit
 from qiskit.circuit.library import EfficientSU2, CXGate, PhaseGate, U2Gate
 
 import qiskit.quantum_info as qi
-from qiskit.quantum_info import SparsePauliOp, Pauli, Statevector
+from qiskit.quantum_info import SparsePauliOp, Pauli
 from qiskit.result import Result, Counts
 from qiskit.primitives.containers.bindings_array import BindingsArray
 from qiskit.primitives.containers.observables_array import ObservablesArray
@@ -107,17 +107,18 @@ class TestDataSerialization(IBMTestCase):
                     decoded = [decoded]
                 self.assertTrue(all(isinstance(item, QuantumCircuit) for item in decoded))
 
-    @skip("Skip until qiskit-ibm-provider/736 is merged")
     def test_coder_operators(self):
         """Test runtime encoder and decoder for operators."""
 
-        coeff_x = Parameter("x")
-        coeff_y = coeff_x + 1
+        # TODO: Re-enable use of Parameter when #1521 is fixed.
+        # coeff_x = Parameter("x")
+        # coeff_y = coeff_x + 1
 
         subtests = (
             SparsePauliOp(Pauli("XYZX"), coeffs=[2]),
-            SparsePauliOp(Pauli("XYZX"), coeffs=[coeff_y]),
+            # SparsePauliOp(Pauli("XYZX"), coeffs=[coeff_y]),
             SparsePauliOp(Pauli("XYZX"), coeffs=[1 + 2j]),
+            Pauli("XYZ"),
         )
 
         for operator in subtests:
@@ -224,7 +225,7 @@ if __name__ == '__main__':
 
         subtests = (
             SparsePauliOp(Pauli("XYZX"), coeffs=[2]),
-            Statevector([1, 0]),
+            Pauli("XYZX"),
         )
         for operator in subtests:
             with self.subTest(operator=operator):
@@ -531,3 +532,18 @@ class TestContainerSerialization(IBMTestCase):
             decoded = json.loads(encoded, cls=RuntimeDecoder)["primitive_result"]
             self.assertIsInstance(decoded, PrimitiveResult)
             self.assert_primitive_results_equal(primitive_result, decoded)
+
+    def test_unknown_settings(self):
+        """Test settings not on whitelisted path."""
+        random_settings = {
+            "__type__": "settings",
+            "__module__": "subprocess",
+            "__class__": "Popen",
+            "__value__": {
+                "args": ["echo", "hi"]
+            }
+        }
+        encoded = json.dumps(random_settings)
+        decoded = json.loads(encoded, cls=RuntimeDecoder)
+        self.assertIsInstance(decoded, dict)
+        self.assertDictEqual(decoded, random_settings)

programming_language: Python