@topy-ai/maggie 0.7.54 → 0.7.56

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 (104) hide show
  1. package/README-zh-TW.md +25 -23
  2. package/README.md +93 -71
  3. package/bin/maggie.js +14 -2
  4. package/bundled-contracts/maggie-assistant-tools/booking-receptionist-example-v1.json +18 -2
  5. package/bundled-contracts/maggie-assistant-tools/report-v1.schema.json +43 -0
  6. package/bundled-contracts/maggie-assistant-tools/tool-registry-example-v1.json +249 -11
  7. package/bundled-contracts/maggie-assistant-tools/tool-registry-v1.schema.json +175 -0
  8. package/bundled-contracts/maggie-deployment/readiness-v1.schema.json +2 -1
  9. package/bundled-contracts/maggie-ops/agent-routines-v1.schema.json +48 -0
  10. package/bundled-contracts/maggie-security/finding-example-v1.json +89 -0
  11. package/bundled-contracts/maggie-security/finding-v1.schema.json +63 -0
  12. package/bundled-contracts/maggie-security/findings-set-example-v1.json +148 -0
  13. package/bundled-contracts/maggie-security/findings-set-v1.schema.json +32 -0
  14. package/bundled-contracts/maggie-security/protect-plan-v1.schema.json +28 -0
  15. package/bundled-contracts/maggie-security/report-v1.schema.json +29 -0
  16. package/bundled-contracts/maggie-security/stack-example-v1.json +66 -0
  17. package/bundled-contracts/maggie-security/stack-upload-v1.schema.json +22 -0
  18. package/bundled-contracts/maggie-security/stack-v1.schema.json +37 -0
  19. package/bundled-contracts/maggie-security/tools-lock-v1.schema.json +36 -0
  20. package/bundled-skills/catalog.json +5 -1
  21. package/bundled-skills/maggie-assistant-tools/SKILL.md +34 -1
  22. package/bundled-skills/maggie-assistant-tools/references/report-inbox.md +45 -0
  23. package/bundled-skills/maggie-assistant-tools/references/unattended-agents.md +70 -0
  24. package/bundled-skills/maggie-blog/SKILL.md +9 -2
  25. package/bundled-skills/maggie-booking/SKILL.md +1 -1
  26. package/bundled-skills/maggie-dash/SKILL.md +9 -0
  27. package/bundled-skills/maggie-deployment/SKILL.md +77 -1
  28. package/bundled-skills/maggie-deployment/references/vps.md +5 -0
  29. package/bundled-skills/maggie-marketplace/SKILL.md +21 -1
  30. package/bundled-skills/maggie-ops/SKILL.md +28 -0
  31. package/bundled-skills/maggie-ops/references/agents-repository.md +108 -0
  32. package/bundled-skills/maggie-ops/references/ops-autopilot.md +65 -0
  33. package/bundled-skills/maggie-ops/references/routine-mode.md +92 -0
  34. package/bundled-skills/maggie-security/SKILL.md +172 -0
  35. package/bundled-skills/maggie-security/agents/openai.yaml +4 -0
  36. package/bundled-skills/maggie-security/data/LICENSE-NOTICE.md +24 -0
  37. package/bundled-skills/maggie-security/data/asvs-map.json +209 -0
  38. package/bundled-skills/maggie-security/data/fail2ban/filter.d/maggie-wordpress.conf +6 -0
  39. package/bundled-skills/maggie-security/data/semgrep/LICENSE-NOTICE.md +5 -0
  40. package/bundled-skills/maggie-security/data/semgrep/VERSION +1 -0
  41. package/bundled-skills/maggie-security/data/semgrep/rules/dockerfile.yaml +14 -0
  42. package/bundled-skills/maggie-security/data/semgrep/rules/generic.yaml +26 -0
  43. package/bundled-skills/maggie-security/data/semgrep/rules/js.yaml +216 -0
  44. package/bundled-skills/maggie-security/data/semgrep/rules/php-debug-ok.yaml +17 -0
  45. package/bundled-skills/maggie-security/data/semgrep/rules/php-debug.yaml +17 -0
  46. package/bundled-skills/maggie-security/data/semgrep/rules/php.yaml +101 -0
  47. package/bundled-skills/maggie-security/data/semgrep/tests/dockerfile.dockerfile +10 -0
  48. package/bundled-skills/maggie-security/data/semgrep/tests/generic.astro +11 -0
  49. package/bundled-skills/maggie-security/data/semgrep/tests/generic.conf +11 -0
  50. package/bundled-skills/maggie-security/data/semgrep/tests/js.jsx +95 -0
  51. package/bundled-skills/maggie-security/data/semgrep/tests/php-debug-ok.php +5 -0
  52. package/bundled-skills/maggie-security/data/semgrep/tests/php-debug.php +3 -0
  53. package/bundled-skills/maggie-security/data/semgrep/tests/php.php +55 -0
  54. package/bundled-skills/maggie-security/evals/evals.json +97 -0
  55. package/bundled-skills/maggie-security/references/commands.md +111 -0
  56. package/bundled-skills/maggie-security/references/cve-response.md +24 -0
  57. package/bundled-skills/maggie-security/references/explaining-findings.md +57 -0
  58. package/bundled-skills/maggie-security/references/findings.md +39 -0
  59. package/bundled-skills/maggie-security/references/ownership-and-consent.md +29 -0
  60. package/bundled-skills/maggie-security/references/site-types.md +22 -0
  61. package/bundled-skills/maggie-security/references/tools-and-licences.md +16 -0
  62. package/bundled-skills/maggie-security/references/workflows.md +23 -0
  63. package/bundled-skills/maggie-security/registry/security-tools.registry.json +628 -0
  64. package/bundled-skills/maggie-security/routines.example.json +27 -0
  65. package/bundled-skills/maggie-seo-geo/SKILL.md +9 -1
  66. package/bundled-skills/maggie-social-share/SKILL.md +20 -0
  67. package/bundled-tools/clis/maggie.py +63 -3
  68. package/bundled-tools/clis/maggie_assistant_tools.py +225 -1
  69. package/bundled-tools/clis/maggie_deployment_readiness.py +17 -2
  70. package/bundled-tools/clis/maggie_host_runtime.py +458 -0
  71. package/bundled-tools/clis/maggie_live_urls.py +11 -2
  72. package/bundled-tools/clis/maggie_ops.py +2 -0
  73. package/bundled-tools/clis/maggie_ops_routines.py +352 -0
  74. package/bundled-tools/clis/maggie_query_ideas.py +154 -0
  75. package/bundled-tools/clis/maggie_security.py +342 -0
  76. package/bundled-tools/clis/maggie_security_agent.py +326 -0
  77. package/bundled-tools/clis/maggie_security_code.py +650 -0
  78. package/bundled-tools/clis/maggie_security_core.py +1512 -0
  79. package/bundled-tools/clis/maggie_security_deps.py +560 -0
  80. package/bundled-tools/clis/maggie_security_health.py +415 -0
  81. package/bundled-tools/clis/maggie_security_host.py +511 -0
  82. package/bundled-tools/clis/maggie_security_hosted.py +115 -0
  83. package/bundled-tools/clis/maggie_security_intel.py +1294 -0
  84. package/bundled-tools/clis/maggie_security_inventory.py +1023 -0
  85. package/bundled-tools/clis/maggie_security_logs.py +777 -0
  86. package/bundled-tools/clis/maggie_security_mcp.py +473 -0
  87. package/bundled-tools/clis/maggie_security_mirror.py +122 -0
  88. package/bundled-tools/clis/maggie_security_protect.py +519 -0
  89. package/bundled-tools/clis/maggie_security_report.py +506 -0
  90. package/bundled-tools/clis/maggie_security_standards.py +214 -0
  91. package/bundled-tools/clis/maggie_security_versions.py +381 -0
  92. package/bundled-tools/clis/maggie_security_web.py +936 -0
  93. package/bundled-tools/clis/maggie_skill_catalog.py +16 -2
  94. package/bundled-tools/clis/maggie_social_share.py +101 -1
  95. package/bundled-tools/clis/maggie_version_sources.py +93 -0
  96. package/bundled-tools/clis/security_data/eol-snapshot.json +1 -0
  97. package/bundled-tools/clis/security_data/gitleaks-rules.json +3812 -0
  98. package/bundled-tools/clis/security_data/maltrail-lists.json +1 -0
  99. package/bundled-tools/clis/security_data/public-suffix-icann.txt +7374 -0
  100. package/bundled-tools/clis/security_data/retire-extractors.json +695 -0
  101. package/bundled-tools/clis/security_data/sigma-web.json +6514 -0
  102. package/bundled-tools/clis/security_data/tools.lock.json +358 -0
  103. package/bundled-tools/integrations/maggie-api-pull.md +28 -1
  104. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ # Data notices
2
+
3
+ Data packaged with Maggie Security and where it comes from. Files listed
4
+ here ship under `tools/clis/security_data/` (bundled with the CLI) or this
5
+ folder.
6
+
7
+ | File | Source | Licence | Notes |
8
+ |---|---|---|---|
9
+ | `tools/clis/security_data/eol-snapshot.json` | endoflife.date `products/*.md` front matter | MIT, © endoflife.date contributors | offline fallback for `eol-watch` |
10
+ | `tools/clis/security_data/retire-extractors.json` | RetireJS/retire.js `repository/jsrepository-v4.json` (extractors only) | Apache-2.0 | detects JavaScript libraries copied into a site |
11
+ | `tools/clis/security_data/gitleaks-rules.json` | gitleaks `config/gitleaks.toml` (222 rules, converted by `scripts/security/build_gitleaks_rules.py`) | MIT, © 2019 Zachary Rice | native secrets engine when the gitleaks binary is not installed |
12
+ | `tools/clis/security_data/tools.lock.json` | Maggie | — | pinned scanner versions and checksums |
13
+ | `tools/clis/security_data/public-suffix-icann.txt` | Public Suffix List (ICANN section, exact rules) via stamparm/maltrail's extract | MPL-2.0, Mozilla Foundation | finds the registrable domain an ownership record covers |
14
+ | `tools/clis/security_data/maltrail-lists.json` | stamparm/maltrail `data/mass_scanner.txt`, `mass_scanner_cidr.txt`, `ua.txt` (commit ef1c67f) | MIT, © 2014-present Maltrail developers | scanner and suspicious user-agent lists for `logs-ioc`; `trails.csv.gz` is not used |
15
+ | `tools/clis/security_data/sigma-web.json` | SigmaHQ/sigma web, proxy and emerging-threat webserver rules (commit 05d1031), built by `scripts/security/build_sigma_pack.py` | Detection Rule License 1.1; author and references kept per rule | `logs-sigma`; every finding carries the rule's title, author, id and licence |
16
+ | `data/semgrep/` | Maggie | MIT | 22 rules written for Maggie, with tests |
17
+ | `data/asvs-map.json` | Maggie | MIT | which commands positively check which ASVS 5.0 requirement; ASVS text itself is read from OWASP at run time (CC BY-SA 4.0) |
18
+ | `data/fail2ban/filter.d/maggie-wordpress.conf` | Maggie | MIT | WordPress login/xmlrpc filter, checked against fail2ban-regex |
19
+ | `registry/security-tools.registry.json` | Maggie | — | MCP/tool registry |
20
+
21
+ Feeds read at run time (not packaged): OSV (per-source licences, mostly
22
+ CC-BY-4.0 and Apache-2.0), CISA KEV (CC0-1.0), FIRST EPSS (free use with
23
+ attribution), CVE List (CVE Terms of Use), Node.js security-wg (MIT),
24
+ WPVulnerability (free API), endoflife.date API (MIT).
@@ -0,0 +1,209 @@
1
+ {
2
+ "schema": "maggie-security-asvs-map.v1",
3
+ "standard": "OWASP ASVS 5.0.0",
4
+ "licence": "MIT (Maggie's mapping; ASVS text is read from OWASP at run time)",
5
+ "note": "coverage = the requirements a command positively checks; silence from a command that does not check a requirement is never a pass (PRD 09 section 7.2).",
6
+ "coverage": {
7
+ "headers": [
8
+ "V3.4.1",
9
+ "V3.4.2",
10
+ "V3.4.3",
11
+ "V3.4.4",
12
+ "V3.4.5",
13
+ "V3.4.6",
14
+ "V3.3.1",
15
+ "V3.3.2",
16
+ "V3.3.4",
17
+ "V12.2.1",
18
+ "V13.4.6"
19
+ ],
20
+ "tls": [
21
+ "V3.4.1",
22
+ "V12.1.1",
23
+ "V12.1.2",
24
+ "V12.2.1",
25
+ "V12.2.2"
26
+ ],
27
+ "web-scan": [
28
+ "V3.4.2",
29
+ "V13.4.1",
30
+ "V13.4.2",
31
+ "V13.4.3",
32
+ "V13.4.4",
33
+ "V13.4.5",
34
+ "V13.4.7",
35
+ "V16.5.1"
36
+ ],
37
+ "host-nginx-config": [
38
+ "V13.4.1",
39
+ "V13.4.2",
40
+ "V13.4.3",
41
+ "V13.4.6",
42
+ "V12.1.1",
43
+ "V12.1.2",
44
+ "V12.2.1",
45
+ "V5.3.2"
46
+ ],
47
+ "secrets": [
48
+ "V13.3.1"
49
+ ],
50
+ "deps": [
51
+ "V15.2.1"
52
+ ],
53
+ "vuln-watch": [
54
+ "V15.2.1"
55
+ ],
56
+ "wp-check": [
57
+ "V15.2.1"
58
+ ],
59
+ "eol-watch": [
60
+ "V15.2.1"
61
+ ],
62
+ "node-check": [
63
+ "V15.2.1"
64
+ ],
65
+ "code-scan": [
66
+ "V1.2.1",
67
+ "V1.2.4",
68
+ "V1.2.5",
69
+ "V1.3.2",
70
+ "V1.3.6",
71
+ "V1.5.2",
72
+ "V3.2.2",
73
+ "V3.7.2",
74
+ "V5.3.2",
75
+ "V8.2.1",
76
+ "V9.1.1",
77
+ "V11.5.1",
78
+ "V13.3.1"
79
+ ],
80
+ "uptime-status": [
81
+ "V12.2.2"
82
+ ]
83
+ },
84
+ "profiles": {
85
+ "static": {
86
+ "chapters": [
87
+ "V3",
88
+ "V12",
89
+ "V13",
90
+ "V15"
91
+ ],
92
+ "exclude_sections": [
93
+ "V3.5",
94
+ "V3.7"
95
+ ]
96
+ },
97
+ "wordpress": {
98
+ "chapters": [
99
+ "V1",
100
+ "V2",
101
+ "V3",
102
+ "V5",
103
+ "V6",
104
+ "V7",
105
+ "V8",
106
+ "V12",
107
+ "V13",
108
+ "V15",
109
+ "V16"
110
+ ],
111
+ "exclude_sections": []
112
+ },
113
+ "node-app": {
114
+ "chapters": [
115
+ "V1",
116
+ "V2",
117
+ "V3",
118
+ "V4",
119
+ "V5",
120
+ "V6",
121
+ "V7",
122
+ "V8",
123
+ "V9",
124
+ "V11",
125
+ "V12",
126
+ "V13",
127
+ "V15",
128
+ "V16"
129
+ ],
130
+ "exclude_sections": []
131
+ },
132
+ "php-app": {
133
+ "chapters": [
134
+ "V1",
135
+ "V2",
136
+ "V3",
137
+ "V5",
138
+ "V6",
139
+ "V7",
140
+ "V8",
141
+ "V9",
142
+ "V11",
143
+ "V12",
144
+ "V13",
145
+ "V15",
146
+ "V16"
147
+ ],
148
+ "exclude_sections": []
149
+ },
150
+ "python-app": {
151
+ "chapters": [
152
+ "V1",
153
+ "V2",
154
+ "V3",
155
+ "V4",
156
+ "V5",
157
+ "V6",
158
+ "V7",
159
+ "V8",
160
+ "V9",
161
+ "V11",
162
+ "V12",
163
+ "V13",
164
+ "V15",
165
+ "V16"
166
+ ],
167
+ "exclude_sections": []
168
+ },
169
+ "java-app": {
170
+ "chapters": [
171
+ "V1",
172
+ "V2",
173
+ "V3",
174
+ "V4",
175
+ "V5",
176
+ "V6",
177
+ "V7",
178
+ "V8",
179
+ "V9",
180
+ "V11",
181
+ "V12",
182
+ "V13",
183
+ "V15",
184
+ "V16"
185
+ ],
186
+ "exclude_sections": []
187
+ },
188
+ "workers": {
189
+ "chapters": [
190
+ "V1",
191
+ "V3",
192
+ "V12",
193
+ "V13",
194
+ "V15"
195
+ ],
196
+ "exclude_sections": []
197
+ },
198
+ "astro": {
199
+ "chapters": [
200
+ "V1",
201
+ "V3",
202
+ "V12",
203
+ "V13",
204
+ "V15"
205
+ ],
206
+ "exclude_sections": []
207
+ }
208
+ }
209
+ }
@@ -0,0 +1,6 @@
1
+ # Maggie WordPress login/xmlrpc brute-force filter (MIT, written for Maggie)
2
+ [Definition]
3
+ failregex = ^<HOST> -[^"]*"POST /(?:[^"/]*/)*wp-login\.php HTTP/[0-9.]+" (?:200|302|403)
4
+ ^<HOST> -[^"]*"POST /(?:[^"/]*/)*xmlrpc\.php HTTP/[0-9.]+" (?:200|403|405)
5
+ ignoreregex =
6
+ datepattern = {^LN-BEG}%%d/%%b/%%Y:%%H:%%M:%%S
@@ -0,0 +1,5 @@
1
+ # Maggie semgrep rule pack
2
+
3
+ Rules written for Maggie (MIT). None is copied from the semgrep registry or
4
+ another rule set. Run only with `maggie security code-scan`, which passes
5
+ `--metrics=off` and never fetches registry rules.
@@ -0,0 +1,14 @@
1
+ rules:
2
+ - id: maggie.docker.secret-in-build-arg
3
+ languages: [dockerfile]
4
+ severity: ERROR
5
+ message: A secret-looking build argument or environment variable has a default value baked into the image. Pass it at run time instead.
6
+ pattern-either:
7
+ - patterns:
8
+ - pattern: 'ARG $NAME=$VALUE'
9
+ - metavariable-regex:
10
+ metavariable: $NAME
11
+ regex: (?i).*(token|secret|password|passwd|api_?key|private_?key).*
12
+ - pattern-regex: (?im)^\s*ENV\s+\w*(token|secret|password|passwd|api_?key|private_?key)\w*(=|\s+)\S+
13
+ metadata: {maggie_id: docker-secret-in-build-arg, cwe: ["CWE-798"], asvs: ["V13.3.1"], confidence: high,
14
+ fix_doc: "https://docs.docker.com/build/building/secrets/"}
@@ -0,0 +1,26 @@
1
+ rules:
2
+ - id: maggie.astro.set-html-untrusted
3
+ languages: [generic]
4
+ paths: {include: ["*.astro"]}
5
+ severity: ERROR
6
+ message: set:html renders HTML from a variable. Sanitize it (DOMPurify, sanitize-html, a markdown renderer that escapes HTML) or use text.
7
+ patterns:
8
+ - pattern-regex: 'set:html=\{(?!\s*(?:["''`][^"''`{}]*["''`]|DOMPurify\.sanitize\(|sanitizeHtml\(|renderMarkdown\())[^}]+\}'
9
+ metadata: {maggie_id: astro-set-html-untrusted, cwe: ["CWE-79"], asvs: ["V1.2.1", "V3.2.2"], confidence: high,
10
+ fix_doc: "https://docs.astro.build/en/reference/directives-reference/#sethtml"}
11
+ - id: maggie.nginx.autoindex-on
12
+ languages: [generic]
13
+ paths: {include: ["*.conf", "nginx.conf*", "*.nginx"]}
14
+ severity: WARNING
15
+ message: Directory listing is on (autoindex on); visitors can browse folders.
16
+ pattern-regex: '(?m)^\s*autoindex\s+on\s*;'
17
+ metadata: {maggie_id: nginx-autoindex-on, cwe: ["CWE-548"], asvs: ["V13.4.3"], confidence: high,
18
+ fix_doc: "https://nginx.org/en/docs/http/ngx_http_autoindex_module.html"}
19
+ - id: maggie.nginx.server-tokens-on
20
+ languages: [generic]
21
+ paths: {include: ["*.conf", "nginx.conf*", "*.nginx"]}
22
+ severity: INFO
23
+ message: nginx shows its version in error pages and headers (server_tokens on).
24
+ pattern-regex: '(?m)^\s*server_tokens\s+on\s*;'
25
+ metadata: {maggie_id: nginx-server-tokens-on, cwe: ["CWE-200"], asvs: ["V13.4.6"], confidence: high,
26
+ fix_doc: "https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens"}
@@ -0,0 +1,216 @@
1
+ rules:
2
+ - id: maggie.react.dangerously-set-inner-html
3
+ languages: [javascript, typescript]
4
+ severity: ERROR
5
+ message: dangerouslySetInnerHTML renders HTML from a variable. Sanitize it first (DOMPurify.sanitize, sanitizeHtml) or render text.
6
+ patterns:
7
+ - pattern: '<$EL dangerouslySetInnerHTML={{__html: $X}} />'
8
+ - pattern-not: '<$EL dangerouslySetInnerHTML={{__html: "..."}} />'
9
+ - pattern-not: '<$EL dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(...)}} />'
10
+ - pattern-not: '<$EL dangerouslySetInnerHTML={{__html: sanitizeHtml(...)}} />'
11
+ - pattern-not: '<$EL dangerouslySetInnerHTML={{__html: renderMarkdown(...)}} />'
12
+ metadata: {maggie_id: react-dangerously-set-inner-html, cwe: ["CWE-79"], asvs: ["V1.2.1", "V3.2.2"], confidence: high,
13
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"}
14
+ - id: maggie.js.eval
15
+ languages: [javascript, typescript]
16
+ severity: ERROR
17
+ message: Code is built from a string at run time (eval, new Function or a string timer). Use a function instead.
18
+ pattern-either:
19
+ - pattern: 'eval($X)'
20
+ - pattern: 'new Function(...)'
21
+ - patterns:
22
+ - pattern-either:
23
+ - pattern: 'setTimeout($S, ...)'
24
+ - pattern: 'setInterval($S, ...)'
25
+ - metavariable-pattern:
26
+ metavariable: $S
27
+ patterns:
28
+ - pattern-either:
29
+ - pattern: '"..."'
30
+ - pattern: '`...`'
31
+ - pattern: '"..." + $Y'
32
+ metadata: {maggie_id: js-eval, cwe: ["CWE-95"], asvs: ["V1.3.2"], confidence: high,
33
+ fix_doc: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_direct_eval!"}
34
+ - id: maggie.js.ssrf-fetch-user-url
35
+ languages: [javascript, typescript]
36
+ severity: ERROR
37
+ message: A server-side request goes to a URL taken from the request. Check it against an allowlist of hosts first.
38
+ mode: taint
39
+ pattern-sources:
40
+ - pattern-either:
41
+ - pattern: '$REQ.query'
42
+ - pattern: '$REQ.body'
43
+ - pattern: '$REQ.params'
44
+ - pattern: '$URL.searchParams.get(...)'
45
+ - pattern: 'await $REQ.json()'
46
+ - pattern: 'await $REQ.formData()'
47
+ pattern-sinks:
48
+ - patterns:
49
+ - pattern-either:
50
+ - pattern: 'fetch($SINK, ...)'
51
+ - pattern: 'axios.get($SINK, ...)'
52
+ - pattern: 'axios.post($SINK, ...)'
53
+ - pattern: 'axios($SINK, ...)'
54
+ - pattern: 'got($SINK, ...)'
55
+ - pattern: 'request($SINK, ...)'
56
+ - focus-metavariable: $SINK
57
+ pattern-sanitizers:
58
+ - pattern-either:
59
+ - pattern: '$ALLOW.includes(...)'
60
+ - pattern: '$ALLOW.has(...)'
61
+ - pattern: 'isAllowedUrl(...)'
62
+ - pattern: 'assertAllowedUrl(...)'
63
+ metadata: {maggie_id: js-ssrf-fetch-user-url, cwe: ["CWE-918"], asvs: ["V1.3.6"], confidence: medium,
64
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html"}
65
+ - id: maggie.js.open-redirect
66
+ languages: [javascript, typescript]
67
+ severity: WARNING
68
+ message: A redirect target comes from the request. Allow only same-site paths or a list of known URLs.
69
+ mode: taint
70
+ pattern-sources:
71
+ - pattern-either:
72
+ - pattern: '$REQ.query'
73
+ - pattern: '$REQ.body'
74
+ - pattern: '$URL.searchParams.get(...)'
75
+ pattern-sinks:
76
+ - patterns:
77
+ - pattern-either:
78
+ - pattern: 'Astro.redirect($T, ...)'
79
+ - pattern: 'Response.redirect($T, ...)'
80
+ - pattern: 'NextResponse.redirect($T, ...)'
81
+ - pattern: '$RES.redirect($T, ...)'
82
+ - pattern: 'redirect($T, ...)'
83
+ - focus-metavariable: $T
84
+ pattern-sanitizers:
85
+ - pattern-either:
86
+ - pattern: 'safeRedirect(...)'
87
+ - pattern: '$ALLOW.includes(...)'
88
+ - pattern: '$X.startsWith("/")'
89
+ metadata: {maggie_id: js-open-redirect, cwe: ["CWE-601"], asvs: ["V3.7.2"], confidence: medium,
90
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html"}
91
+ - id: maggie.js.insecure-cookie
92
+ languages: [javascript, typescript]
93
+ severity: WARNING
94
+ message: A session or auth cookie is set without httpOnly, secure and sameSite.
95
+ patterns:
96
+ - pattern-either:
97
+ - pattern: '$C.set($NAME, $V, $OPTS)'
98
+ - pattern: '$RES.cookie($NAME, $V, $OPTS)'
99
+ - metavariable-regex:
100
+ metavariable: $NAME
101
+ regex: (?i).*(sess|auth|token|login|sid|jwt|remember).*
102
+ - metavariable-pattern:
103
+ metavariable: $OPTS
104
+ patterns:
105
+ - pattern: '{...}'
106
+ - pattern-not: '{..., httpOnly: true, ..., secure: true, ..., sameSite: $S, ...}'
107
+ - pattern-not: '{..., secure: true, ..., httpOnly: true, ..., sameSite: $S, ...}'
108
+ - pattern-not: '{..., sameSite: $S, ..., httpOnly: true, ..., secure: true, ...}'
109
+ - pattern-not: '{..., httpOnly: true, ..., sameSite: $S, ..., secure: true, ...}'
110
+ - pattern-not: '{..., secure: true, ..., sameSite: $S, ..., httpOnly: true, ...}'
111
+ - pattern-not: '{..., sameSite: $S, ..., secure: true, ..., httpOnly: true, ...}'
112
+ metadata: {maggie_id: js-insecure-cookie, cwe: ["CWE-614", "CWE-1004"], asvs: ["V3.3.1", "V3.3.2"], confidence: high,
113
+ fix_doc: "https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#security"}
114
+ - id: maggie.js.jwt-none-or-unverified
115
+ languages: [javascript, typescript]
116
+ severity: ERROR
117
+ message: The token is decoded without checking its signature, or the 'none' algorithm is allowed. Use jwt.verify with an explicit algorithm list.
118
+ pattern-either:
119
+ - pattern: 'jwt.decode(...)'
120
+ - pattern: |
121
+ jwt.verify($T, $K, {..., algorithms: [..., "none", ...], ...})
122
+ metadata: {maggie_id: js-jwt-none-or-unverified, cwe: ["CWE-347"], asvs: ["V9.1.1"], confidence: medium,
123
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html"}
124
+ - id: maggie.js.child-process-user-input
125
+ languages: [javascript, typescript]
126
+ severity: ERROR
127
+ message: A shell command is built from request data. Pass arguments as an array without a shell, and validate them.
128
+ mode: taint
129
+ pattern-sources:
130
+ - pattern-either:
131
+ - pattern: '$REQ.query'
132
+ - pattern: '$REQ.body'
133
+ - pattern: '$REQ.params'
134
+ - pattern: '$URL.searchParams.get(...)'
135
+ pattern-sinks:
136
+ - patterns:
137
+ - pattern-either:
138
+ - pattern: 'exec($CMD, ...)'
139
+ - pattern: 'execSync($CMD, ...)'
140
+ - pattern: 'child_process.exec($CMD, ...)'
141
+ - pattern: 'child_process.execSync($CMD, ...)'
142
+ - pattern: 'spawn($CMD, $ARGS, {..., shell: true, ...})'
143
+ - focus-metavariable: $CMD
144
+ metadata: {maggie_id: js-child-process-user-input, cwe: ["CWE-78"], asvs: ["V1.2.5"], confidence: high,
145
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html"}
146
+ - id: maggie.js.path-traversal
147
+ languages: [javascript, typescript]
148
+ severity: ERROR
149
+ message: A file path comes from the request. Resolve it and check it stays inside the allowed folder.
150
+ mode: taint
151
+ pattern-sources:
152
+ - pattern-either:
153
+ - pattern: '$REQ.query'
154
+ - pattern: '$REQ.params'
155
+ - pattern: '$REQ.body'
156
+ - pattern: '$URL.searchParams.get(...)'
157
+ pattern-sinks:
158
+ - patterns:
159
+ - pattern-either:
160
+ - pattern: 'fs.readFile($P, ...)'
161
+ - pattern: 'fs.readFileSync($P, ...)'
162
+ - pattern: 'fs.createReadStream($P, ...)'
163
+ - pattern: 'readFile($P, ...)'
164
+ - pattern: 'fs.promises.readFile($P, ...)'
165
+ - focus-metavariable: $P
166
+ pattern-sanitizers:
167
+ - pattern: 'safeJoin(...)'
168
+ - pattern: 'path.basename(...)'
169
+ metadata: {maggie_id: js-path-traversal, cwe: ["CWE-22"], asvs: ["V5.3.2"], confidence: high,
170
+ fix_doc: "https://owasp.org/www-community/attacks/Path_Traversal"}
171
+ - id: maggie.js.cors-wildcard-credentials
172
+ languages: [javascript, typescript]
173
+ severity: WARNING
174
+ message: CORS allows any origin together with credentials, or echoes the Origin header without checking it.
175
+ pattern-either:
176
+ - patterns:
177
+ - pattern-inside: |
178
+ $H.set("Access-Control-Allow-Credentials", "true");
179
+ ...
180
+ - pattern: '$H.set("Access-Control-Allow-Origin", $REQ.headers.get("origin"))'
181
+ - pattern: |
182
+ {..., origin: true, ..., credentials: true, ...}
183
+ - pattern: |
184
+ {..., origin: "*", ..., credentials: true, ...}
185
+ metadata: {maggie_id: js-cors-wildcard-credentials, cwe: ["CWE-942"], asvs: ["V3.4.2"], confidence: medium,
186
+ fix_doc: "https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"}
187
+ - id: maggie.js.secret-in-client-env
188
+ languages: [javascript, typescript]
189
+ severity: ERROR
190
+ message: A public build variable is named like a secret; anything with this prefix is sent to every visitor's browser.
191
+ patterns:
192
+ - pattern-either:
193
+ - pattern: 'import.meta.env.$NAME'
194
+ - pattern: 'process.env.$NAME'
195
+ - metavariable-regex:
196
+ metavariable: $NAME
197
+ regex: ^(PUBLIC|NEXT_PUBLIC|VITE|NUXT_PUBLIC|REACT_APP|EXPO_PUBLIC)_\w*(SECRET|PRIVATE|SERVICE_ROLE|TOKEN|PASSWORD|API_KEY)\w*$
198
+ - metavariable-regex:
199
+ metavariable: $NAME
200
+ regex: ^(?!.*(PUBLISHABLE|SITE_KEY|ANON_KEY)).*$
201
+ metadata: {maggie_id: js-secret-in-client-env, cwe: ["CWE-200"], asvs: ["V13.3.1"], confidence: high,
202
+ fix_doc: "https://docs.astro.build/en/guides/environment-variables/"}
203
+ - id: maggie.js.math-random-token
204
+ languages: [javascript, typescript]
205
+ severity: WARNING
206
+ message: Math.random() is not secure for tokens. Use crypto.randomUUID() or crypto.getRandomValues().
207
+ patterns:
208
+ - pattern-either:
209
+ - pattern: 'const $V = <... Math.random() ...>;'
210
+ - pattern: 'let $V = <... Math.random() ...>;'
211
+ - pattern: '$OBJ.$V = <... Math.random() ...>;'
212
+ - metavariable-regex:
213
+ metavariable: $V
214
+ regex: (?i).*(token|secret|otp|nonce|password|session|key|code).*
215
+ metadata: {maggie_id: js-math-random-token, cwe: ["CWE-338"], asvs: ["V11.5.1"], confidence: high,
216
+ fix_doc: "https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues"}
@@ -0,0 +1,17 @@
1
+ rules:
2
+ - id: maggie.php.debug-on
3
+ languages: [php]
4
+ severity: WARNING
5
+ message: WordPress debug output is on in committed config; errors will be shown to visitors.
6
+ patterns:
7
+ - pattern: 'define(''WP_DEBUG'', true);'
8
+ - pattern-not-inside: |
9
+ define('WP_DEBUG', true);
10
+ ...
11
+ define('WP_DEBUG_DISPLAY', false);
12
+ - pattern-not-inside: |
13
+ define('WP_DEBUG_DISPLAY', false);
14
+ ...
15
+ define('WP_DEBUG', true);
16
+ metadata: {maggie_id: php-debug-on, cwe: ["CWE-489"], asvs: ["V13.4.2"], confidence: high,
17
+ fix_doc: "https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/"}
@@ -0,0 +1,17 @@
1
+ rules:
2
+ - id: maggie.php.debug-on
3
+ languages: [php]
4
+ severity: WARNING
5
+ message: WordPress debug output is on in committed config; errors will be shown to visitors.
6
+ patterns:
7
+ - pattern: 'define(''WP_DEBUG'', true);'
8
+ - pattern-not-inside: |
9
+ define('WP_DEBUG', true);
10
+ ...
11
+ define('WP_DEBUG_DISPLAY', false);
12
+ - pattern-not-inside: |
13
+ define('WP_DEBUG_DISPLAY', false);
14
+ ...
15
+ define('WP_DEBUG', true);
16
+ metadata: {maggie_id: php-debug-on, cwe: ["CWE-489"], asvs: ["V13.4.2"], confidence: high,
17
+ fix_doc: "https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/"}
@@ -0,0 +1,101 @@
1
+ rules:
2
+ - id: maggie.php.sql-concat
3
+ languages: [php]
4
+ severity: ERROR
5
+ message: SQL is built by joining strings with a variable. Use $wpdb->prepare() or a prepared statement.
6
+ patterns:
7
+ - pattern-either:
8
+ - pattern: '$DB->query($Q)'
9
+ - pattern: '$DB->get_results($Q, ...)'
10
+ - pattern: '$DB->get_row($Q, ...)'
11
+ - pattern: '$DB->get_var($Q, ...)'
12
+ - pattern: '$DB->get_col($Q, ...)'
13
+ - pattern: 'mysqli_query($C, $Q, ...)'
14
+ - metavariable-pattern:
15
+ metavariable: $Q
16
+ patterns:
17
+ - pattern-either:
18
+ - pattern: '"..." . $X'
19
+ - pattern: '$X . "..."'
20
+ - pattern: '"...$X..."'
21
+ - pattern-not: '$DB->prepare(...)'
22
+ metadata: {maggie_id: php-sql-concat, cwe: ["CWE-89"], asvs: ["V1.2.4"], confidence: high,
23
+ fix_doc: "https://developer.wordpress.org/reference/classes/wpdb/prepare/"}
24
+ - id: maggie.php.unescaped-output
25
+ languages: [php]
26
+ severity: ERROR
27
+ message: Request data is printed without escaping. Wrap it in esc_html(), esc_attr(), esc_url() or wp_kses().
28
+ patterns:
29
+ - pattern-either:
30
+ - pattern: 'echo <... $_GET[...] ...>;'
31
+ - pattern: 'echo <... $_POST[...] ...>;'
32
+ - pattern: 'echo <... $_REQUEST[...] ...>;'
33
+ - pattern: 'echo <... $_COOKIE[...] ...>;'
34
+ - pattern: 'echo <... get_query_var(...) ...>;'
35
+ - pattern: 'print <... $_GET[...] ...>;'
36
+ - pattern-not: 'echo <... esc_html(...) ...>;'
37
+ - pattern-not: 'echo <... esc_attr(...) ...>;'
38
+ - pattern-not: 'echo <... esc_url(...) ...>;'
39
+ - pattern-not: 'echo <... wp_kses(...) ...>;'
40
+ - pattern-not: 'echo <... htmlspecialchars(...) ...>;'
41
+ - pattern-not: 'echo <... intval(...) ...>;'
42
+ - pattern-not: 'echo <... absint(...) ...>;'
43
+ metadata: {maggie_id: php-unescaped-output, cwe: ["CWE-79"], asvs: ["V1.2.1", "V3.2.2"], confidence: high,
44
+ fix_doc: "https://developer.wordpress.org/apis/security/escaping/"}
45
+ - id: maggie.php.missing-nonce
46
+ languages: [php]
47
+ severity: WARNING
48
+ message: An AJAX/admin-post handler reads $_POST without checking a nonce (check_ajax_referer or wp_verify_nonce).
49
+ patterns:
50
+ - pattern-inside: |
51
+ function $F(...) { ... }
52
+ - pattern: '$_POST[...]'
53
+ - pattern-not-inside: |
54
+ function $F(...) { ... check_ajax_referer(...); ... }
55
+ - pattern-not-inside: |
56
+ function $F(...) { ... wp_verify_nonce(...); ... }
57
+ - pattern-not-inside: |
58
+ function $F(...) { ... check_admin_referer(...); ... }
59
+ - pattern-not-inside: |
60
+ function $F(...) { ... if (<... wp_verify_nonce(...) ...>) { ... } ... }
61
+ metadata: {maggie_id: php-missing-nonce, cwe: ["CWE-352"], asvs: ["V3.5.1"], confidence: medium,
62
+ fix_doc: "https://developer.wordpress.org/apis/security/nonces/"}
63
+ - id: maggie.php.missing-capability
64
+ languages: [php]
65
+ severity: ERROR
66
+ message: A REST route that changes data lets anyone call it (permission_callback __return_true).
67
+ pattern-either:
68
+ - pattern: |
69
+ register_rest_route($NS, $R, [..., 'methods' => $M, ..., 'permission_callback' => '__return_true', ...]);
70
+ - pattern: |
71
+ register_rest_route($NS, $R, array(..., 'methods' => $M, ..., 'permission_callback' => '__return_true', ...));
72
+ metadata: {maggie_id: php-missing-capability, cwe: ["CWE-862"], asvs: ["V8.2.1"], confidence: medium,
73
+ fix_doc: "https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#permissions-callback"}
74
+ - id: maggie.php.file-include-user
75
+ languages: [php]
76
+ severity: ERROR
77
+ message: A file is included from a path that comes from the request.
78
+ pattern-either:
79
+ - pattern: 'include <... $_GET[...] ...>;'
80
+ - pattern: 'include <... $_POST[...] ...>;'
81
+ - pattern: 'include <... $_REQUEST[...] ...>;'
82
+ - pattern: 'include_once <... $_GET[...] ...>;'
83
+ - pattern: 'require <... $_GET[...] ...>;'
84
+ - pattern: 'require_once <... $_GET[...] ...>;'
85
+ - pattern: 'require_once <... $_REQUEST[...] ...>;'
86
+ metadata: {maggie_id: php-file-include-user, cwe: ["CWE-98"], asvs: ["V5.3.2"], confidence: high,
87
+ fix_doc: "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion"}
88
+ - id: maggie.php.unserialize-user
89
+ languages: [php]
90
+ severity: ERROR
91
+ message: Request data is unserialized. Use json_decode() instead.
92
+ pattern-either:
93
+ - pattern: 'unserialize(<... $_GET[...] ...>, ...)'
94
+ - pattern: 'unserialize(<... $_POST[...] ...>, ...)'
95
+ - pattern: 'unserialize(<... $_COOKIE[...] ...>, ...)'
96
+ - pattern: 'unserialize(<... $_REQUEST[...] ...>, ...)'
97
+ - pattern: 'maybe_unserialize(<... $_POST[...] ...>)'
98
+ - pattern: 'maybe_unserialize(<... $_GET[...] ...>)'
99
+ - pattern: 'maybe_unserialize(<... $_COOKIE[...] ...>)'
100
+ metadata: {maggie_id: php-unserialize-user, cwe: ["CWE-502"], asvs: ["V1.5.2"], confidence: high,
101
+ fix_doc: "https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html"}
@@ -0,0 +1,10 @@
1
+ FROM node:20-alpine
2
+ # ruleid: maggie.docker.secret-in-build-arg
3
+ ARG NPM_TOKEN=abc123
4
+ # ok: maggie.docker.secret-in-build-arg
5
+ ARG NODE_ENV=production
6
+ # ruleid: maggie.docker.secret-in-build-arg
7
+ ENV DB_PASSWORD=hunter2hunter2
8
+ # ok: maggie.docker.secret-in-build-arg
9
+ ARG SENTRY_TOKEN
10
+ USER node
@@ -0,0 +1,11 @@
1
+ ---
2
+ const { post } = Astro.props;
3
+ ---
4
+ <!-- ruleid: maggie.astro.set-html-untrusted -->
5
+ <article set:html={post.body} />
6
+ <!-- ok: maggie.astro.set-html-untrusted -->
7
+ <p set:html={"<b>static</b>"} />
8
+ <!-- ok: maggie.astro.set-html-untrusted -->
9
+ <div set:html={DOMPurify.sanitize(post.body)} />
10
+ <!-- ruleid: maggie.astro.set-html-untrusted -->
11
+ <div set:html={post.excerpt + "..."} />