T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/quantum_sim.py:104
- Finding
- Dense gate construction permits severe memory-exhaustion denial of service<![CDATA[ ## Vulnerability Details **File Location**: `scripts/quantum_sim.py:104-132` **Vulnerability Type**: Uncontrolled memory allocation / algorithmic denial of service **Risk Level**: High ### Vulnerable Code ```python class QuantumCircuit: def __init__(self, n_qubits: int): if n_qubits < 1 or n_qubits > 20: raise ValueError("Qubit count must be 1-20") self.n = n_qubits self.dim = 1 << n_qubits # 2^n self.state = _zeros(self.dim) self.state[0] = 1+0j self.log: List[str] = [] def _apply_single(self, gate_mat, qubit: int): """Apply a single-qubit gate to the statevector.""" n = self.n if _USE_NUMPY: op = np.array([[1+0j]]) for i in range(n-1, -1, -1): if i == qubit: op = np.kron(op, np.array(gate_mat, dtype=complex)) else: op = np.kron(op, np.eye(2, dtype=complex)) self.state = op @ self.state else: op = [[1+0j]] for i in range(n-1, -1, -1): if i == qubit: op = _kron(op, gate_mat) else: op = _kron(op, _I2) self.state = _matmul_vec(op, self.state) ``` ### Technical Analysis The constructor accepts up to 20 qubits, for which the statevector contains `2^20` amplitudes. However, applying any single-qubit gate does not update those amplitudes directly. Instead, `_apply_single` constructs a complete dense `2^n × 2^n` operator through repeated Kronecker products. At 20 qubits, the resulting matrix contains `2^40` complex values. With NumPy `complex128` values, the final matrix alone would require approximately 16 TiB of memory, excluding temporary arrays produced by repeated `np.kron` operations. The pure-Python fallback has even greater object and list overhead. This behavior conflicts with the documented implication that a 20-qubit simulation ...[truncated 1780 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace dense operator construction with an in-place or bounded-copy statevector update. For a single-qubit gate, iterate over amplitude pairs whose indices differ only at the target-qubit bit: ```python def _apply_single(self, gate, qubit): step = 1 << qubit span = step << 1 for base in range(0, self.dim, span): for offset in range(step): i0 = base + offset i1 = i0 + step a0 = self.state[i0] a1 = self.state[i1] self.state[i0] = gate[0][0] * a0 + gate[0][1] * a1 self.state[i1] = gate[1][0] * a0 + gate[1][1] * a1 ``` This reduces auxiliary memory from `O(4^n)` to `O(1)` and performs `O(2^n)` arithmetic per gate. 2. Apply explicit resource budgeting before allocating the statevector. Calculate the required statevector size from the selected representation and reject requests exceeding a configurable memory allowance. 3. If dense matrix construction is retained, lower the maximum qubit count to a value proven safe for the runtime environment. This is inferior to direct statevector updates and should only be a temporary mitigation. 4. Add automated tests for the documented maximum qubit count and monitor peak resident memory, not merely the final statevector size. 5. Run simulations inside a process or container with enforceable memory and CPU limits so an unexpected allocation cannot exhaust the host. ]]>
