YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
Unhandled TypeError (float(None)) importing a PMML SupportVectorMachineModel whose kernel element omits gamma/coef0/degree (spec-default) β load-time DoS
Target
- Project:
sklearn-pmml-model(PyPI:sklearn-pmml-model) - Version tested: 1.0.8 (installed from PyPI)
- Runtime: Python 3.13, scikit-learn 1.9.0
- Affected file:
sklearn_pmml_model/svm/_base.py,PMMLBaseSVM.__init__(lines 72β86) - Affected estimators / entrypoints:
PMMLSVC,PMMLSVR(both subclassPMMLBaseSVM), and thesklearn_pmml_model.auto_detectdispatcher that routes anySupportVectorMachineModelPMML to these classes.
Summary
PMMLBaseSVM.__init__ parses the SVM kernel parameters from the PMML kernel
element with no defaults and no type guards. When a spec-valid PMML file
omits an optional kernel attribute (e.g. gamma), Element.get('gamma')
returns None, and the subsequent float(None) / int(None) raises an
unhandled TypeError during model construction β before any prediction is
attempted. Because there is no try/except around construction, loading an
untrusted PMML file crashes the caller: a load-time denial of service.
Per the DMG PMML v4.x specification (http://dmg.org/pmml/v4-3/SupportVectorMachineModel.html), these kernel attributes are OPTIONAL with documented defaults:
RadialBasisKernelType:gammadefault1PolynomialKernelType:gammadefault1,coef0default1,degreedefault1SigmoidKernelType:gammadefault1,coef0default1
A PMML producer that relies on any of these documented defaults emits a perfectly spec-valid file that this loader cannot parse.
Root cause
sklearn_pmml_model/svm/_base.py, PMMLBaseSVM.__init__:
linear = model.find('LinearKernelType')
poly = model.find('PolynomialKernelType')
rbf = model.find('RadialBasisKernelType')
sigmoid = model.find('SigmoidKernelType')
if linear is not None:
self.kernel = 'linear'
self._gamma = self.gamma = 0.0
elif poly is not None:
self.kernel = 'poly'
self._gamma = self.gamma = float(poly.get('gamma')) # line 77 -> float(None) if absent
self.coef0 = float(poly.get('coef0')) # line 78 -> float(None) if absent
self.degree = int(poly.get('degree')) # line 79 -> int(None) if absent
elif rbf is not None:
self.kernel = 'rbf'
self._gamma = self.gamma = float(rbf.get('gamma')) # line 82 -> float(None) if absent [PoC trigger]
elif sigmoid is not None:
self.kernel = 'sigmoid'
self._gamma = self.gamma = float(sigmoid.get('gamma')) # line 85 -> float(None) if absent
self.coef0 = float(sigmoid.get('coef0')) # line 86 -> float(None) if absent
Element.get(name) returns None when the attribute is absent. float(None)
and int(None) raise TypeError. The spec says these attributes are optional
with defaults, so the correct behavior would be to fall back to the documented
default (e.g. poly.get('gamma', 1) / ... or 1) rather than crash.
Proof of concept
Two PMML files differing by exactly one attribute isolate the cause:
- Negative control β
svc-baseline.pmml: a real SVC PMML whose kernel is<RadialBasisKernelType gamma="0.09090909090909091"/>. Loads successfully. - PoC β
svc-nogamma.pmml: byte-for-byte identical except the singlegammaattribute is removed, leaving<RadialBasisKernelType/>(spec-valid; relies on thegammadefault of1). Loading raisesTypeErroratsvm/_base.py:82.
from sklearn_pmml_model.svm import PMMLSVC
# Negative control β succeeds
m = PMMLSVC(pmml='svc-baseline.pmml')
print('BASELINE OK kernel=', m.kernel, 'gamma=', m.gamma)
# PoC β raises TypeError during construction (no prediction call)
m = PMMLSVC(pmml='svc-nogamma.pmml')
Sibling attack surfaces (same no-default pattern)
The identical unguarded-get pattern also crashes for:
PolynomialKernelTypemissinggamma/coef0/degree(lines 77β79)SigmoidKernelTypemissinggamma/coef0(lines 85β86)
Captured evidence (verbatim)
Run under the installed sklearn-pmml-model==1.0.8, Python 3.13:
=== BASELINE ===
BASELINE OK kernel= rbf gamma= 0.09090909090909091
=== POC ===
Traceback (most recent call last):
File "<string>", line 3, in <module>
m = PMMLSVC(pmml='/home/kali/hunt-workspace/pmml-13thbug/svc-nogamma.pmml')
File "/home/kali/hunt-workspace/pmml-12thbug-venv/lib/python3.13/site-packages/sklearn_pmml_model/svm/_classes.py", line 249, in __init__
PMMLBaseSVM.__init__(self)
~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/home/kali/hunt-workspace/pmml-12thbug-venv/lib/python3.13/site-packages/sklearn_pmml_model/svm/_base.py", line 82, in __init__
self._gamma = self.gamma = float(rbf.get('gamma'))
~~~~~^^^^^^^^^^^^^^^^^^
TypeError: float() argument must be a string or a real number, not 'NoneType'
Impact
- Type: Load-time denial of service (unhandled exception during model construction) when importing an untrusted / third-party PMML file.
- Trigger: A spec-valid
SupportVectorMachineModelPMML that relies on any documented default for a kernel attribute. No malformed input required. - Reachability: Reached by
PMMLSVC,PMMLSVR, and theauto_detectdispatcher β the standard public entrypoints for loading SVM PMML models. No prediction call is needed; the crash occurs in__init__.
Suggested fix
Apply the spec defaults instead of passing None into float/int, e.g.:
self._gamma = self.gamma = float(rbf.get('gamma', 1))
# poly:
self._gamma = self.gamma = float(poly.get('gamma', 1))
self.coef0 = float(poly.get('coef0', 1))
self.degree = int(poly.get('degree', 1))
# sigmoid:
self._gamma = self.gamma = float(sigmoid.get('gamma', 1))
self.coef0 = float(sigmoid.get('coef0', 1))
Dedup note
This is distinct from other sklearn-pmml-model findings in this program:
- The SVM coefficient-count mismatch finding concerns
<Coefficients>/ support-vector pairing, not kernel-attribute parsing. - The GLM/linreg/logreg/kNN
TypeErrorfindings concern different modules (_classes.pyfor those estimators), different elements, and different parameters.
This finding is specific to svm/_base.py:72β86 kernel-attribute parsing
(float(None)/int(None) on absent optional attributes). No known CVE
corresponds to this specific crash site.