Summary
When using Card.get_model
, skops
allows for arbitrary code execution. This is due to the fact that Card.get_model
allows both joblib
and skops
to be used for loading models, and as is well known, joblib
allows for arbitrary code execution when loading objects. I do not know if this is intended or not, but I found this really concerning for a library that is founded on security. Even if intended, I kindly ask you to consider the security implications of this, disclose the potential implications through an advisory, and change the behavior of the function in future library versions (see below for possible fixes).
What is the issue?
The Card.get_model
function allows loading models using the get_model
method. When a .skops
model is provided, it uses the load
function from skops
, which is secure to our knowledge. The Card
class also allows consistent management of the trusted
list, allowing it to be passed during instance creation. As expected, if a skops
model is provided without a trusted
list, and an untrusted type is found during loading, it will raise an error. This is perfectly fine and consistent with the security principles of skops
.
The problem arises when a file format different from a .zip
file is provided. In this case, as shown in the code snippet below, the joblib
library is used to load the model. This happens silently, without any warning or indication that the model is being loaded using joblib
. This is a significant security risk, as joblib
does not enforce the same security measures as skops
, allowing for arbitrary code execution
# from `card/_model_card.py:354-358`
try:
if zipfile.is_zipfile(model_path):
model = load(model_path, trusted=trusted)
else:
model = joblib.load(model_path)
Hence, for example, a simple code like the following will execute arbitrary code:
from skops.card import Card
card = Card("model.skops")
clf = card.get_model()
In this case, despite the name, the model.skops
file is not a .zip
file, and thus the joblib.load
function is called, allowing for arbitrary code execution. This is also difficult to spot for the user, since the check is transparent and performed on the file's nature, not on the file extension or name.
Note: this happens despite the trusted
list being passed during the Card
instance creation or any other parameter.
Impact
An attacker can exploit this vulnerability by crafting a malicious model file that, when loaded using Card.get_model
, executes arbitrary code on the victim's machine. The attack does not require any special privileges or additional steps from the victim; simply loading the model is sufficient to trigger the execution of the attacker's code. The attack happens silently and at loading time, making it particularly stealthy and difficult to detect. This is particularly concerning if we consider that Card.get_model
and skops
are often used in collaborative environments and that skops
promotes a security-oriented policy.
Thank you for your attention to this matter. I hope this report helps improve the security of the Card.get_model
function and the overall security posture of the skops
library.
References
Summary
When using
Card.get_model
,skops
allows for arbitrary code execution. This is due to the fact thatCard.get_model
allows bothjoblib
andskops
to be used for loading models, and as is well known,joblib
allows for arbitrary code execution when loading objects. I do not know if this is intended or not, but I found this really concerning for a library that is founded on security. Even if intended, I kindly ask you to consider the security implications of this, disclose the potential implications through an advisory, and change the behavior of the function in future library versions (see below for possible fixes).What is the issue?
The
Card.get_model
function allows loading models using theget_model
method. When a.skops
model is provided, it uses theload
function fromskops
, which is secure to our knowledge. TheCard
class also allows consistent management of thetrusted
list, allowing it to be passed during instance creation. As expected, if askops
model is provided without atrusted
list, and an untrusted type is found during loading, it will raise an error. This is perfectly fine and consistent with the security principles ofskops
.The problem arises when a file format different from a
.zip
file is provided. In this case, as shown in the code snippet below, thejoblib
library is used to load the model. This happens silently, without any warning or indication that the model is being loaded usingjoblib
. This is a significant security risk, asjoblib
does not enforce the same security measures asskops
, allowing for arbitrary code executionHence, for example, a simple code like the following will execute arbitrary code:
In this case, despite the name, the
model.skops
file is not a.zip
file, and thus thejoblib.load
function is called, allowing for arbitrary code execution. This is also difficult to spot for the user, since the check is transparent and performed on the file's nature, not on the file extension or name.Note: this happens despite the
trusted
list being passed during theCard
instance creation or any other parameter.Impact
An attacker can exploit this vulnerability by crafting a malicious model file that, when loaded using
Card.get_model
, executes arbitrary code on the victim's machine. The attack does not require any special privileges or additional steps from the victim; simply loading the model is sufficient to trigger the execution of the attacker's code. The attack happens silently and at loading time, making it particularly stealthy and difficult to detect. This is particularly concerning if we consider thatCard.get_model
andskops
are often used in collaborative environments and thatskops
promotes a security-oriented policy.Thank you for your attention to this matter. I hope this report helps improve the security of the
Card.get_model
function and the overall security posture of theskops
library.References