# sklearn-pmml-model SVM: SupportVector/Coefficient count mismatch → IndexError crash importing a PMML SupportVectorMachineModel ## Summary `sklearn-pmml-model` crashes with an unhandled `IndexError` inside the model constructor when importing a PMML file whose `` contains **fewer `` elements than `` elements**. Importing arbitrary PMML is the library's core purpose, and the two element lists are independent, attacker-controlled inputs with no bound or consistency check between them. - **Target package:** `sklearn-pmml-model` (PyPI) - **Version tested:** `1.0.8` (confirmed latest on PyPI) - **Vulnerable file:** `sklearn_pmml_model/svm/_base.py`, function `get_coefficients()` (lines ~201-204) - **Crash type:** `IndexError` (unhandled exception) during `PMMLSVC(...)` construction - **Reachable entry points:** direct `PMMLSVC(path)` constructor **and** the high-level `auto_detect_estimator(path)` dispatcher - **Environment:** clean venv, Python 3.13.12, numpy from `sklearn-pmml-model==1.0.8` deps ## Root cause In `get_coefficients()` the code parses two **independent** child-element lists of a single `` — the `` ids and the `` values — then uses positions computed against the first list to index into the second array: ```python # sklearn_pmml_model/svm/_base.py (lines ~196-204) for j, svm in enumerate(alt_svms): start = offsets[i] end = offsets[i + 1] ids = support_ids[start:end] support_vectors = [int(x.get('vectorId')) for x in svm.find('SupportVectors').findall('SupportVector')] coefficients = [float(x.get('value')) for x in svm.find('Coefficients').findall('Coefficient')] indices = [support_vectors.index(x) for x in ids] dual_coef[j, start:end] = np.array(coefficients)[indices] # <-- line 204: IndexError ``` `indices` are positions into the **SupportVector** list (`support_vectors`), but they are applied to a **different** array, `np.array(coefficients)`. Nothing couples or validates `len()` against `len()`. When a PMML supplies fewer `` elements than `` elements, an index that is valid for the SupportVector list exceeds the bounds of the coefficients array, and numpy raises `IndexError` inside the constructor. The counts are pure element-count values taken straight from untrusted XML. ## PoC Starting material is the project's **own valid example** model `models/svc-cat-pima.pmml` (fetched from the upstream repo). It loads cleanly: 36 `` / 36 ``, `dual_coef` shape `(1, 36)`. `svc-mismatch.pmml` is that file with **all but the first `` deleted** inside the single `` block (now 36 `` / 1 ``); everything else is byte-identical. Loading it raises `IndexError` at `svm/_base.py` line 204. **Negative control:** the unmodified 36/36 file loads OK through both the direct constructor and `auto_detect_estimator` (as `PMMLSVC`, `dual_coef (1, 36)`), proving the crash is caused solely by the SupportVector-vs-Coefficient count mismatch, not by any other structural change. ### Reproduce ```bash python -m venv venv && . venv/bin/activate pip install sklearn-pmml-model==1.0.8 python repro.py ``` `repro.py`: ```python import traceback from sklearn_pmml_model.svm import PMMLSVC def run(path, label): print(f"=== {label}: {path} ===") try: m = PMMLSVC(path) print(" OK -> dual_coef", m.dual_coef_.shape) except Exception as e: tb = traceback.extract_tb(e.__traceback__)[-1] print(" CRASH", type(e).__name__ + ":", e) print(" SITE", tb.filename.split('site-packages/')[-1], "line", tb.lineno) run("svc-cat-pima.pmml", "NEGATIVE CONTROL (36 SupportVectors / 36 Coefficients)") run("svc-mismatch.pmml", "POSITIVE (36 SupportVectors / 1 Coefficient)") ``` ## Captured evidence (verbatim, real execution) ``` === NEGATIVE CONTROL (36 SupportVectors / 36 Coefficients): svc-cat-pima.pmml === OK -> dual_coef (1, 36) === POSITIVE (36 SupportVectors / 1 Coefficient): svc-mismatch.pmml === CRASH IndexError: index 1 is out of bounds for axis 0 with size 1 SITE sklearn_pmml_model/svm/_base.py line 204 ``` Full traceback (direct constructor): ``` Traceback (most recent call last): File "", line 3, in PMMLSVC('svc-mismatch.pmml') ~~~~~~~^^^^^^^^^^^^^^^^^^^^^ File ".../sklearn_pmml_model/svm/_classes.py", line 249, in __init__ PMMLBaseSVM.__init__(self) ~~~~~~~~~~~~~~~~~~~~^^^^^^ File ".../sklearn_pmml_model/svm/_base.py", line 61, in __init__ get_coefficients(classes, self._n_support, self.support_, svms) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File ".../sklearn_pmml_model/svm/_base.py", line 204, in get_coefficients dual_coef[j, start:end] = np.array(coefficients)[indices] ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^ IndexError: index 1 is out of bounds for axis 0 with size 1 ``` Also reproduced via the public entry point: ``` auto_detect_estimator('svc-mismatch.pmml') -> IndexError, SITE svm/_base.py line 204 auto_detect_estimator('svc-cat-pima.pmml') -> OK, PMMLSVC, dual_coef (1, 36) ``` ## Impact Any application that imports a user-/third-party-supplied PMML SVM model via this library (its intended use case) can be crashed with an unhandled `IndexError` by supplying a mismatched ``/`` count. This is a denial-of-service / robustness defect on untrusted model-file input. A benign example file can be turned into a crashing payload by deleting a single XML element. ## Suggested fix Validate `len(coefficients) == len(support_vectors)` (and that both match the declared support count) before indexing, and raise a clear parse error (e.g. a PMML validation exception) instead of letting numpy raise `IndexError`. ## Dedup note This is distinct from prior `sklearn-pmml-model` findings: - SparseArray index/value pairing crash (TreeModel/other) — different file/parser. - TreeModel recursion / NeuralNetwork allocation DoS — different model type and code path. - PMML XXE — an XML-layer issue, not an SVM value-consistency issue. This bug is specific to `svm/_base.py::get_coefficients()` and the SupportVector-vs-Coefficient element-count mismatch. No public CVE was found for this specific SVM coefficient-indexing crash at time of writing.