muaddib-scanner 1.0.8 → 1.0.10

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.
Files changed (37) hide show
  1. package/.muaddib-cache/iocs.json +355 -0
  2. package/README.fr.md +310 -0
  3. package/README.md +118 -93
  4. package/bin/muaddib.js +33 -26
  5. package/data/iocs.json +28 -0
  6. package/package.json +3 -3
  7. package/rapport.html +159 -0
  8. package/src/index.js +73 -15
  9. package/src/ioc/scraper.js +91 -50
  10. package/src/rules/index.js +40 -1
  11. package/src/scanner/typosquat.js +52 -118
  12. package/.github/workflows/scan.yml +0 -33
  13. package/docs/threat-model.md +0 -116
  14. package/test/samples/malicious.js +0 -20
  15. package/tests/run-tests.js +0 -389
  16. package/tests/samples/ast/malicious.js +0 -20
  17. package/tests/samples/clean/safe.js +0 -14
  18. package/tests/samples/dataflow/exfiltration.js +0 -20
  19. package/tests/samples/edge/empty/empty.js +0 -0
  20. package/tests/samples/edge/invalid-syntax/broken.js +0 -5
  21. package/tests/samples/edge/large-file/large.js +0 -6
  22. package/tests/samples/edge/non-js/readme.txt +0 -3
  23. package/tests/samples/markers/shai-hulud.js +0 -10
  24. package/tests/samples/obfuscation/obfuscated.js +0 -1
  25. package/tests/samples/package/package.json +0 -9
  26. package/tests/samples/shell/malicious.sh +0 -13
  27. package/tests/samples/typosquat/package.json +0 -11
  28. package/vscode-extension/.vscode/launch.json +0 -13
  29. package/vscode-extension/.vscodeignore +0 -0
  30. package/vscode-extension/LICENSE +0 -21
  31. package/vscode-extension/README.md +0 -0
  32. package/vscode-extension/extension.js +0 -271
  33. package/vscode-extension/icon.png +0 -0
  34. package/vscode-extension/muaddib-vscode-1.0.0.vsix +0 -0
  35. package/vscode-extension/package.json +0 -64
  36. package/vscode-extension/vscode-extension/README.md +0 -44
  37. package/vscode-extension/vscode-extension/package.json +0 -64
@@ -0,0 +1,355 @@
1
+ {
2
+ "packages": [
3
+ {
4
+ "name": "@ctrl/tinycolor",
5
+ "version": "4.1.1",
6
+ "source": "shai-hulud-v1"
7
+ },
8
+ {
9
+ "name": "ng2-file-upload",
10
+ "version": "*",
11
+ "source": "shai-hulud-v1"
12
+ },
13
+ {
14
+ "name": "ngx-bootstrap",
15
+ "version": "*",
16
+ "source": "shai-hulud-v1"
17
+ },
18
+ {
19
+ "name": "@asyncapi/specs",
20
+ "version": "*",
21
+ "source": "shai-hulud-v2"
22
+ },
23
+ {
24
+ "name": "@asyncapi/openapi-schema-parser",
25
+ "version": "*",
26
+ "source": "shai-hulud-v2"
27
+ },
28
+ {
29
+ "name": "get-them-args",
30
+ "version": "*",
31
+ "source": "shai-hulud-v2"
32
+ },
33
+ {
34
+ "name": "kill-port",
35
+ "version": "*",
36
+ "source": "shai-hulud-v2"
37
+ },
38
+ {
39
+ "name": "shell-exec",
40
+ "version": "*",
41
+ "source": "shai-hulud-v2"
42
+ },
43
+ {
44
+ "name": "posthog-node",
45
+ "version": "*",
46
+ "source": "shai-hulud-v2"
47
+ },
48
+ {
49
+ "name": "posthog-js",
50
+ "version": "*",
51
+ "source": "shai-hulud-v2"
52
+ },
53
+ {
54
+ "name": "@postman/tunnel-agent",
55
+ "version": "*",
56
+ "source": "shai-hulud-v2"
57
+ },
58
+ {
59
+ "name": "@zapier/secret-scrubber",
60
+ "version": "*",
61
+ "source": "shai-hulud-v2"
62
+ },
63
+ {
64
+ "name": "@vietmoney/react-big-calendar",
65
+ "version": "0.26.2",
66
+ "source": "shai-hulud-v3"
67
+ },
68
+ {
69
+ "name": "flatmap-stream",
70
+ "version": "0.1.1",
71
+ "source": "event-stream-2018"
72
+ },
73
+ {
74
+ "name": "event-stream",
75
+ "version": "3.3.6",
76
+ "source": "event-stream-2018"
77
+ },
78
+ {
79
+ "name": "eslint-scope",
80
+ "version": "3.7.2",
81
+ "source": "eslint-scope-2018"
82
+ },
83
+ {
84
+ "name": "eslint-config-prettier",
85
+ "version": "8.10.1",
86
+ "source": "eslint-prettier-2025"
87
+ },
88
+ {
89
+ "name": "eslint-config-prettier",
90
+ "version": "9.1.1",
91
+ "source": "eslint-prettier-2025"
92
+ },
93
+ {
94
+ "name": "eslint-plugin-prettier",
95
+ "version": "4.2.2",
96
+ "source": "eslint-prettier-2025"
97
+ },
98
+ {
99
+ "name": "synckit",
100
+ "version": "0.11.9",
101
+ "source": "eslint-prettier-2025"
102
+ },
103
+ {
104
+ "name": "@pkgr/core",
105
+ "version": "0.2.8",
106
+ "source": "eslint-prettier-2025"
107
+ },
108
+ {
109
+ "name": "napi-postinstall",
110
+ "version": "0.3.1",
111
+ "source": "eslint-prettier-2025"
112
+ },
113
+ {
114
+ "name": "got-fetch",
115
+ "version": "5.1.11",
116
+ "source": "eslint-prettier-2025"
117
+ },
118
+ {
119
+ "name": "is",
120
+ "version": "3.3.1",
121
+ "source": "is-package-2025"
122
+ },
123
+ {
124
+ "name": "is",
125
+ "version": "5.0.0",
126
+ "source": "is-package-2025"
127
+ },
128
+ {
129
+ "name": "crossenv",
130
+ "version": "*",
131
+ "source": "typosquat"
132
+ },
133
+ {
134
+ "name": "cross-env.js",
135
+ "version": "*",
136
+ "source": "typosquat"
137
+ },
138
+ {
139
+ "name": "mongose",
140
+ "version": "*",
141
+ "source": "typosquat"
142
+ },
143
+ {
144
+ "name": "mssql.js",
145
+ "version": "*",
146
+ "source": "typosquat"
147
+ },
148
+ {
149
+ "name": "mssql-node",
150
+ "version": "*",
151
+ "source": "typosquat"
152
+ },
153
+ {
154
+ "name": "babelcli",
155
+ "version": "*",
156
+ "source": "typosquat"
157
+ },
158
+ {
159
+ "name": "http-proxy.js",
160
+ "version": "*",
161
+ "source": "typosquat"
162
+ },
163
+ {
164
+ "name": "proxy.js",
165
+ "version": "*",
166
+ "source": "typosquat"
167
+ },
168
+ {
169
+ "name": "shadowsock",
170
+ "version": "*",
171
+ "source": "typosquat"
172
+ },
173
+ {
174
+ "name": "smb",
175
+ "version": "*",
176
+ "source": "typosquat"
177
+ },
178
+ {
179
+ "name": "nodesass",
180
+ "version": "*",
181
+ "source": "typosquat"
182
+ },
183
+ {
184
+ "name": "node-sass.js",
185
+ "version": "*",
186
+ "source": "typosquat"
187
+ },
188
+ {
189
+ "name": "node-ipc",
190
+ "version": "10.1.1",
191
+ "source": "protestware"
192
+ },
193
+ {
194
+ "name": "node-ipc",
195
+ "version": "10.1.2",
196
+ "source": "protestware"
197
+ },
198
+ {
199
+ "name": "node-ipc",
200
+ "version": "10.1.3",
201
+ "source": "protestware"
202
+ },
203
+ {
204
+ "name": "colors",
205
+ "version": "1.4.1",
206
+ "source": "protestware"
207
+ },
208
+ {
209
+ "name": "colors",
210
+ "version": "1.4.2",
211
+ "source": "protestware"
212
+ },
213
+ {
214
+ "name": "faker",
215
+ "version": "6.6.6",
216
+ "source": "protestware"
217
+ },
218
+ {
219
+ "name": "ua-parser-js",
220
+ "version": "0.7.29",
221
+ "source": "community",
222
+ "description": "Compromis octobre 2021 - crypto miner"
223
+ },
224
+ {
225
+ "name": "coa",
226
+ "version": "2.0.3",
227
+ "source": "community",
228
+ "description": "Compromis novembre 2021"
229
+ },
230
+ {
231
+ "name": "coa",
232
+ "version": "2.0.4",
233
+ "source": "community",
234
+ "description": "Compromis novembre 2021"
235
+ },
236
+ {
237
+ "name": "rc",
238
+ "version": "1.2.9",
239
+ "source": "community",
240
+ "description": "Compromis novembre 2021"
241
+ },
242
+ {
243
+ "name": "rc",
244
+ "version": "1.3.9",
245
+ "source": "community",
246
+ "description": "Compromis novembre 2021"
247
+ },
248
+ {
249
+ "name": "left-pad",
250
+ "version": "*",
251
+ "source": "community",
252
+ "description": "Incident 2016 - supply chain"
253
+ },
254
+ {
255
+ "name": "lodash-merge",
256
+ "version": "*",
257
+ "source": "typosquat",
258
+ "description": "Typosquat de lodash.merge"
259
+ },
260
+ {
261
+ "name": "loadash",
262
+ "version": "*",
263
+ "source": "typosquat",
264
+ "description": "Typosquat de lodash"
265
+ },
266
+ {
267
+ "name": "electorn",
268
+ "version": "*",
269
+ "source": "typosquat",
270
+ "description": "Typosquat de electron"
271
+ },
272
+ {
273
+ "name": "discord.js-selfbot-v11",
274
+ "version": "*",
275
+ "source": "community",
276
+ "description": "Token stealer Discord"
277
+ },
278
+ {
279
+ "name": "discord-selfbot-tools",
280
+ "version": "*",
281
+ "source": "community",
282
+ "description": "Token stealer Discord"
283
+ },
284
+ {
285
+ "name": "discordsystem",
286
+ "version": "*",
287
+ "source": "community",
288
+ "description": "Token stealer Discord"
289
+ },
290
+ {
291
+ "name": "discord-lofy",
292
+ "version": "*",
293
+ "source": "community",
294
+ "description": "Token stealer Discord"
295
+ },
296
+ {
297
+ "name": "prerequests",
298
+ "version": "*",
299
+ "source": "typosquat",
300
+ "description": "Typosquat de prerequests"
301
+ },
302
+ {
303
+ "name": "requstes",
304
+ "version": "*",
305
+ "source": "typosquat",
306
+ "description": "Typosquat de requests"
307
+ }
308
+ ],
309
+ "files": [
310
+ "setup_bun.js",
311
+ "bun_environment.js",
312
+ "bundle.js",
313
+ "node-gyp.dll",
314
+ "preinstall.js",
315
+ "postinstall.js",
316
+ "install.js",
317
+ "discord-webhook.js",
318
+ "token-grabber.js",
319
+ "stealer.js",
320
+ "inject.js"
321
+ ],
322
+ "hashes": [
323
+ "62ee164b9b306250c1172583f138c9614139264f889fa99614903c12755468d0",
324
+ "cbb9bc5a8496243e02f3cc080efbe3e4a1430ba0671f2e43a202bf45b05479cd",
325
+ "f099c5d9ec417d4445a0328ac0ada9cde79fc37410914103ae9c609cbc0ee068",
326
+ "a3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a",
327
+ "f1df4896244500671eb4aa63ebb48ea11cee196fafaa0e9874e17b24ac053c02",
328
+ "9d59fd0bcc14b671079824c704575f201b74276238dc07a9c12a93a84195648a",
329
+ "e0250076c1d2ac38777ea8f542431daf61fcbaab0ca9c196614b28065ef5b918",
330
+ "6c9628f72d2bb789fe8f097a611d61c8c53f2f21e47c6a5d8d3e0e0b8e5e8c8f",
331
+ "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
332
+ "4b2399646573bb737c4969563303d8ee2e9ddbd1b271f1ca9e35ea78062538db",
333
+ "46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09",
334
+ "b74caeaa75e077c99f7d44f46daaf9796a3be43ecf24f2a1fd381844669da777",
335
+ "dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c",
336
+ "8f3c4e2a1b5d6c7e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e",
337
+ "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
338
+ ],
339
+ "markers": [
340
+ "Sha1-Hulud",
341
+ "Shai-Hulud",
342
+ "The Second Coming",
343
+ "Goldox-T3chs",
344
+ "Only Happy Girl",
345
+ "peacenotwar",
346
+ "protestware",
347
+ "/dev/tcp",
348
+ "reverse shell",
349
+ "discord.com/api/webhooks",
350
+ "token grabber",
351
+ "crypto miner",
352
+ "xmrig"
353
+ ],
354
+ "updated": "2026-01-02T09:21:30.216Z"
355
+ }
package/README.fr.md ADDED
@@ -0,0 +1,310 @@
1
+ <p align="center">
2
+ <img src="MUADDIBLOGO.png" alt="MUAD'DIB Logo" width="200">
3
+ </p>
4
+
5
+ <h1 align="center">MUAD'DIB</h1>
6
+
7
+ <p align="center">
8
+ <strong>Supply-chain threat detection & response for npm</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <img src="https://img.shields.io/npm/v/muaddib-scanner" alt="npm version">
13
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="License">
14
+ <img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node">
15
+ <img src="https://img.shields.io/badge/IOCs-180%2B-red" alt="IOCs">
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="#installation">Installation</a> |
20
+ <a href="#utilisation">Utilisation</a> |
21
+ <a href="#features">Features</a> |
22
+ <a href="#vs-code">VS Code</a> |
23
+ <a href="#discord">Discord</a>
24
+ </p>
25
+
26
+ ---
27
+
28
+ ## Pourquoi MUAD'DIB ?
29
+
30
+ Les attaques supply chain npm explosent. Shai-Hulud a compromis 25K+ repos en 2025. Les outils existants detectent, mais n'aident pas a repondre.
31
+
32
+ MUAD'DIB detecte ET guide la reponse.
33
+
34
+ | Feature | MUAD'DIB | Socket | Snyk |
35
+ |---------|----------|--------|------|
36
+ | Detection IOCs | Oui | Oui | Oui |
37
+ | Analyse AST | Oui | Oui | Non |
38
+ | Analyse Dataflow | Oui | Non | Non |
39
+ | Detection Typosquatting | Oui | Oui | Non |
40
+ | Playbooks reponse | Oui | Non | Non |
41
+ | Score de risque | Oui | Oui | Oui |
42
+ | SARIF / GitHub Security | Oui | Oui | Oui |
43
+ | MITRE ATT&CK mapping | Oui | Non | Non |
44
+ | Webhook Discord/Slack | Oui | Non | Non |
45
+ | Extension VS Code | Oui | Oui | Oui |
46
+ | Mode daemon | Oui | Non | Non |
47
+ | 100% Open Source | Oui | Non | Non |
48
+
49
+ ---
50
+
51
+ ## Installation
52
+
53
+ ### npm (recommande)
54
+ ```bash
55
+ npm install -g muaddib-scanner
56
+ ```
57
+
58
+ ### Depuis les sources
59
+ ```bash
60
+ git clone https://github.com/DNSZLSK/muad-dib.git
61
+ cd muad-dib
62
+ npm install
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Utilisation
68
+
69
+ ### Scan basique
70
+ ```bash
71
+ muaddib scan .
72
+ muaddib scan /chemin/vers/projet
73
+ ```
74
+
75
+ ### Score de risque
76
+
77
+ Chaque scan affiche un score de risque 0-100 :
78
+ ```
79
+ [SCORE] 58/100 [███████████░░░░░░░░░] HIGH
80
+ ```
81
+
82
+ ### Mode explain (details complets)
83
+ ```bash
84
+ muaddib scan . --explain
85
+ ```
86
+
87
+ Affiche pour chaque detection :
88
+ - Rule ID
89
+ - MITRE ATT&CK technique
90
+ - References (articles, CVEs)
91
+ - Playbook de reponse
92
+
93
+ ### Export
94
+ ```bash
95
+ muaddib scan . --json > results.json # JSON
96
+ muaddib scan . --html rapport.html # HTML
97
+ muaddib scan . --sarif results.sarif # SARIF (GitHub Security)
98
+ ```
99
+
100
+ ### Seuil de severite
101
+ ```bash
102
+ muaddib scan . --fail-on critical # Fail seulement sur CRITICAL
103
+ muaddib scan . --fail-on high # Fail sur HIGH et CRITICAL (defaut)
104
+ muaddib scan . --fail-on medium # Fail sur MEDIUM, HIGH, CRITICAL
105
+ ```
106
+
107
+ ### Webhook Discord/Slack
108
+ ```bash
109
+ muaddib scan . --webhook "https://discord.com/api/webhooks/..."
110
+ ```
111
+
112
+ Envoie une alerte avec le score et les menaces sur Discord ou Slack.
113
+
114
+ ### Surveillance temps reel
115
+ ```bash
116
+ muaddib watch .
117
+ ```
118
+
119
+ ### Mode daemon
120
+ ```bash
121
+ muaddib daemon
122
+ muaddib daemon --webhook "https://discord.com/api/webhooks/..."
123
+ ```
124
+
125
+ Surveille automatiquement tous les `npm install` et scanne les nouveaux packages.
126
+
127
+ ### Mise a jour des IOCs
128
+ ```bash
129
+ muaddib update
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Features
135
+
136
+ ### Detection typosquatting
137
+
138
+ MUAD'DIB detecte les packages dont le nom ressemble a un package populaire :
139
+ ```
140
+ [HIGH] Package "lodahs" ressemble a "lodash" (swapped_chars). Possible typosquatting.
141
+ ```
142
+
143
+ ### Analyse dataflow
144
+
145
+ Detecte quand du code lit des credentials ET les envoie sur le reseau :
146
+ ```
147
+ [CRITICAL] Flux suspect: lecture credentials (readFileSync, GITHUB_TOKEN) + envoi reseau (fetch)
148
+ ```
149
+
150
+ ### Attaques detectees
151
+
152
+ | Campagne | Packages | Status |
153
+ |----------|----------|--------|
154
+ | Shai-Hulud v1 | @ctrl/tinycolor, ng2-file-upload | Detecte |
155
+ | Shai-Hulud v2 | @asyncapi/specs, posthog-node, kill-port | Detecte |
156
+ | Shai-Hulud v3 | @vietmoney/react-big-calendar | Detecte |
157
+ | event-stream (2018) | flatmap-stream, event-stream | Detecte |
158
+ | eslint-scope (2018) | eslint-scope | Detecte |
159
+ | Protestware | node-ipc, colors, faker | Detecte |
160
+ | Typosquats | crossenv, mongose, babelcli | Detecte |
161
+
162
+ ### Techniques detectees
163
+
164
+ | Technique | MITRE | Detection |
165
+ |-----------|-------|-----------|
166
+ | Vol credentials (.npmrc, .ssh) | T1552.001 | AST |
167
+ | Exfiltration env vars | T1552.001 | AST |
168
+ | Execution code distant | T1105 | Pattern |
169
+ | Reverse shell | T1059.004 | Pattern |
170
+ | Dead man's switch | T1485 | Pattern |
171
+ | Code obfusque | T1027 | Heuristiques |
172
+ | Typosquatting | T1195.002 | Levenshtein |
173
+ | Supply chain compromise | T1195.002 | IOC matching |
174
+
175
+ ---
176
+
177
+ ## VS Code
178
+
179
+ L'extension VS Code scanne automatiquement vos projets npm.
180
+
181
+ ### Installation
182
+
183
+ Le dossier `vscode-extension/` contient l'extension. Pour tester :
184
+
185
+ 1. Ouvrir le dossier `vscode-extension` dans VS Code
186
+ 2. Appuyer sur F5
187
+ 3. Dans la nouvelle fenetre, ouvrir un projet npm
188
+
189
+ ### Commandes
190
+
191
+ - `MUAD'DIB: Scan Project` - Scanner tout le projet
192
+ - `MUAD'DIB: Scan Current File` - Scanner le fichier actuel
193
+
194
+ ### Configuration
195
+
196
+ - `muaddib.autoScan` - Scanner automatiquement a l'ouverture (defaut: true)
197
+ - `muaddib.webhookUrl` - URL webhook Discord/Slack
198
+ - `muaddib.failLevel` - Niveau d'alerte (critical/high/medium/low)
199
+
200
+ ---
201
+
202
+ ## Integration CI/CD
203
+
204
+ ### GitHub Actions
205
+ ```yaml
206
+ name: Security Scan
207
+
208
+ on: [push, pull_request]
209
+
210
+ jobs:
211
+ scan:
212
+ runs-on: ubuntu-latest
213
+ permissions:
214
+ security-events: write
215
+ contents: read
216
+ steps:
217
+ - uses: actions/checkout@v4
218
+ - uses: actions/setup-node@v4
219
+ with:
220
+ node-version: '20'
221
+ - run: npm install -g muaddib-scanner
222
+ - run: muaddib scan . --sarif results.sarif
223
+ - uses: github/codeql-action/upload-sarif@v3
224
+ with:
225
+ sarif_file: results.sarif
226
+ ```
227
+
228
+ Les alertes apparaissent dans Security > Code scanning alerts.
229
+
230
+ ---
231
+
232
+ ## Discord
233
+
234
+ Rejoignez le serveur Discord pour :
235
+ - Recevoir les alertes de scan
236
+ - Partager des IOCs
237
+ - Contribuer au projet
238
+
239
+ ---
240
+
241
+ ## Architecture
242
+ ```
243
+ MUAD'DIB Scanner
244
+ |
245
+ +-- IOC Match (YAML DB)
246
+ +-- AST Parse (acorn)
247
+ +-- Pattern Matching (shell, scripts)
248
+ +-- Typosquat Detection (Levenshtein)
249
+ |
250
+ v
251
+ Dataflow Analysis (credential read -> network send)
252
+ |
253
+ v
254
+ Threat Enrichment (rules, MITRE ATT&CK, playbooks)
255
+ |
256
+ v
257
+ Output (CLI, JSON, HTML, SARIF, Webhook)
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Contribuer
263
+
264
+ ### Ajouter des IOCs
265
+
266
+ Editez les fichiers YAML dans `iocs/` :
267
+ ```yaml
268
+ - id: NEW-MALWARE-001
269
+ name: "malicious-package"
270
+ version: "*"
271
+ severity: critical
272
+ confidence: high
273
+ source: community
274
+ description: "Description de la menace"
275
+ references:
276
+ - https://example.com/article
277
+ mitre: T1195.002
278
+ ```
279
+
280
+ ### Developper
281
+ ```bash
282
+ git clone https://github.com/DNSZLSK/muad-dib.git
283
+ cd muad-dib
284
+ npm install
285
+ npm test
286
+ ```
287
+
288
+ ## Communaute
289
+
290
+ - Discord: https://discord.gg/y8zxSmue
291
+ - Issues: https://github.com/DNSZLSK/muad-dib/issues
292
+
293
+ ---
294
+
295
+ ## Documentation
296
+
297
+ - [Threat Model](docs/threat-model.md) - Ce que MUAD'DIB detecte et ne detecte pas
298
+ - [IOCs YAML](iocs/) - Base de donnees des menaces
299
+
300
+ ---
301
+
302
+ ## Licence
303
+
304
+ MIT
305
+
306
+ ---
307
+
308
+ <p align="center">
309
+ <strong>The spice must flow. The worms must die.</strong>
310
+ </p>