mcpwall 0.1.0
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/LICENSE +105 -0
- package/README.md +230 -0
- package/dist/index.js +1106 -0
- package/package.json +57 -0
- package/rules/default.yml +114 -0
- package/rules/strict.yml +226 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcpwall",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deterministic security proxy for MCP tool calls — iptables for MCP. Blocks dangerous tool calls, scans for secret leakage, logs everything. No AI, no cloud, pure rules.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcpwall": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"rules"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"prepublishOnly": "npm run build && chmod +x dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"firewall",
|
|
22
|
+
"security",
|
|
23
|
+
"proxy",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"claude",
|
|
26
|
+
"ai-safety",
|
|
27
|
+
"tool-call",
|
|
28
|
+
"json-rpc",
|
|
29
|
+
"audit"
|
|
30
|
+
],
|
|
31
|
+
"author": "Dom Behrens",
|
|
32
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/behrensd/mcp-firewall.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/behrensd/mcp-firewall",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/behrensd/mcp-firewall/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"commander": "^14.0.3",
|
|
46
|
+
"minimatch": "^10.2.0",
|
|
47
|
+
"yaml": "^2.8.2",
|
|
48
|
+
"zod": "^4.3.6"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/minimatch": "^5.1.2",
|
|
52
|
+
"@types/node": "^25.2.3",
|
|
53
|
+
"tsup": "^8.5.1",
|
|
54
|
+
"typescript": "^5.9.3",
|
|
55
|
+
"vitest": "^4.0.18"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
settings:
|
|
4
|
+
log_dir: ~/.mcpwall/logs
|
|
5
|
+
log_level: info
|
|
6
|
+
default_action: allow
|
|
7
|
+
|
|
8
|
+
rules:
|
|
9
|
+
# === FILE ACCESS PROTECTION ===
|
|
10
|
+
- name: block-ssh-keys
|
|
11
|
+
match:
|
|
12
|
+
method: tools/call
|
|
13
|
+
tool: "*"
|
|
14
|
+
arguments:
|
|
15
|
+
_any_value:
|
|
16
|
+
regex: "(\\.ssh/|id_rsa|id_ed25519|id_ecdsa)"
|
|
17
|
+
action: deny
|
|
18
|
+
message: "Blocked: access to SSH keys"
|
|
19
|
+
|
|
20
|
+
- name: block-env-files
|
|
21
|
+
match:
|
|
22
|
+
method: tools/call
|
|
23
|
+
tool: "*"
|
|
24
|
+
arguments:
|
|
25
|
+
_any_value:
|
|
26
|
+
regex: "/\\.env($|\\.)"
|
|
27
|
+
action: deny
|
|
28
|
+
message: "Blocked: access to .env files"
|
|
29
|
+
|
|
30
|
+
- name: block-credentials
|
|
31
|
+
match:
|
|
32
|
+
method: tools/call
|
|
33
|
+
tool: "*"
|
|
34
|
+
arguments:
|
|
35
|
+
_any_value:
|
|
36
|
+
regex: "(\\.aws/credentials|\\.npmrc|\\.docker/config\\.json|\\.kube/config|\\.gnupg/)"
|
|
37
|
+
action: deny
|
|
38
|
+
message: "Blocked: access to credential files"
|
|
39
|
+
|
|
40
|
+
- name: block-browser-data
|
|
41
|
+
match:
|
|
42
|
+
method: tools/call
|
|
43
|
+
tool: "*"
|
|
44
|
+
arguments:
|
|
45
|
+
_any_value:
|
|
46
|
+
regex: "(Chrome|Firefox|Safari)/(Default|Profile|Cookies|Login Data)"
|
|
47
|
+
action: deny
|
|
48
|
+
message: "Blocked: access to browser data"
|
|
49
|
+
|
|
50
|
+
# === DANGEROUS COMMANDS ===
|
|
51
|
+
- name: block-destructive-commands
|
|
52
|
+
match:
|
|
53
|
+
method: tools/call
|
|
54
|
+
tool: "*"
|
|
55
|
+
arguments:
|
|
56
|
+
_any_value:
|
|
57
|
+
regex: "(rm\\s+-r|rm\\s+-f|rmdir\\s+/|mkfs|dd\\s+if=|format\\s+[A-Z]:)"
|
|
58
|
+
action: deny
|
|
59
|
+
message: "Blocked: destructive command"
|
|
60
|
+
|
|
61
|
+
- name: block-pipe-to-shell
|
|
62
|
+
match:
|
|
63
|
+
method: tools/call
|
|
64
|
+
tool: "*"
|
|
65
|
+
arguments:
|
|
66
|
+
_any_value:
|
|
67
|
+
regex: "(curl|wget|fetch).*\\|.*(bash|sh|zsh|python|node)"
|
|
68
|
+
action: deny
|
|
69
|
+
message: "Blocked: piping remote content to shell"
|
|
70
|
+
|
|
71
|
+
- name: block-reverse-shells
|
|
72
|
+
match:
|
|
73
|
+
method: tools/call
|
|
74
|
+
tool: "*"
|
|
75
|
+
arguments:
|
|
76
|
+
_any_value:
|
|
77
|
+
regex: "(nc\\s+-[le]|/dev/tcp/|bash\\s+-i\\s+>&|mkfifo|socat)"
|
|
78
|
+
action: deny
|
|
79
|
+
message: "Blocked: potential reverse shell"
|
|
80
|
+
|
|
81
|
+
# === SECRET LEAKAGE ===
|
|
82
|
+
- name: block-secret-leakage
|
|
83
|
+
match:
|
|
84
|
+
method: tools/call
|
|
85
|
+
tool: "*"
|
|
86
|
+
arguments:
|
|
87
|
+
_any_value:
|
|
88
|
+
secrets: true
|
|
89
|
+
action: deny
|
|
90
|
+
message: "Blocked: detected secret/API key in tool arguments"
|
|
91
|
+
|
|
92
|
+
secrets:
|
|
93
|
+
patterns:
|
|
94
|
+
- name: aws-access-key
|
|
95
|
+
regex: "AKIA[0-9A-Z]{16}"
|
|
96
|
+
- name: aws-secret-key
|
|
97
|
+
regex: "[A-Za-z0-9/+=]{40}"
|
|
98
|
+
entropy_threshold: 4.5
|
|
99
|
+
- name: github-token
|
|
100
|
+
regex: "(gh[ps]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9_]{22,})"
|
|
101
|
+
- name: openai-key
|
|
102
|
+
regex: "sk-[A-Za-z0-9]{20,}"
|
|
103
|
+
- name: anthropic-key
|
|
104
|
+
regex: "sk-ant-[A-Za-z0-9-]{20,}"
|
|
105
|
+
- name: stripe-key
|
|
106
|
+
regex: "(sk|pk|rk)_(test|live)_[A-Za-z0-9]{24,}"
|
|
107
|
+
- name: private-key-header
|
|
108
|
+
regex: "-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----"
|
|
109
|
+
- name: jwt-token
|
|
110
|
+
regex: "eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}"
|
|
111
|
+
- name: slack-token
|
|
112
|
+
regex: "xox[bpoas]-[A-Za-z0-9-]+"
|
|
113
|
+
- name: database-url
|
|
114
|
+
regex: "(postgres|mysql|mongodb|redis)://[^\\s]+"
|
package/rules/strict.yml
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
settings:
|
|
4
|
+
log_dir: ~/.mcpwall/logs
|
|
5
|
+
log_level: debug
|
|
6
|
+
default_action: deny
|
|
7
|
+
|
|
8
|
+
rules:
|
|
9
|
+
# === EXPLICIT ALLOWS (whitelist mode) ===
|
|
10
|
+
# Only allow reading files under project directory
|
|
11
|
+
- name: allow-project-reads
|
|
12
|
+
match:
|
|
13
|
+
method: tools/call
|
|
14
|
+
tool: "read_file"
|
|
15
|
+
arguments:
|
|
16
|
+
path:
|
|
17
|
+
not_under: "${PROJECT_DIR}"
|
|
18
|
+
action: deny
|
|
19
|
+
message: "Strict mode: file reads restricted to project directory"
|
|
20
|
+
|
|
21
|
+
- name: allow-project-reads-pass
|
|
22
|
+
match:
|
|
23
|
+
method: tools/call
|
|
24
|
+
tool: "read_file"
|
|
25
|
+
action: allow
|
|
26
|
+
|
|
27
|
+
# Only allow writing files under project directory
|
|
28
|
+
- name: block-external-writes
|
|
29
|
+
match:
|
|
30
|
+
method: tools/call
|
|
31
|
+
tool: "write_file"
|
|
32
|
+
arguments:
|
|
33
|
+
path:
|
|
34
|
+
not_under: "${PROJECT_DIR}"
|
|
35
|
+
action: deny
|
|
36
|
+
message: "Strict mode: file writes restricted to project directory"
|
|
37
|
+
|
|
38
|
+
- name: allow-project-writes-pass
|
|
39
|
+
match:
|
|
40
|
+
method: tools/call
|
|
41
|
+
tool: "write_file"
|
|
42
|
+
action: allow
|
|
43
|
+
|
|
44
|
+
# Allow listing files under project directory
|
|
45
|
+
- name: allow-list-files
|
|
46
|
+
match:
|
|
47
|
+
method: tools/call
|
|
48
|
+
tool: "list_directory"
|
|
49
|
+
action: allow
|
|
50
|
+
|
|
51
|
+
# Allow search within project
|
|
52
|
+
- name: allow-search
|
|
53
|
+
match:
|
|
54
|
+
method: tools/call
|
|
55
|
+
tool: "search_files"
|
|
56
|
+
action: allow
|
|
57
|
+
|
|
58
|
+
# === FILE ACCESS PROTECTION ===
|
|
59
|
+
- name: block-ssh-keys
|
|
60
|
+
match:
|
|
61
|
+
method: tools/call
|
|
62
|
+
tool: "*"
|
|
63
|
+
arguments:
|
|
64
|
+
_any_value:
|
|
65
|
+
regex: "(\\.ssh/|id_rsa|id_ed25519|id_ecdsa|authorized_keys)"
|
|
66
|
+
action: deny
|
|
67
|
+
message: "Blocked: access to SSH keys"
|
|
68
|
+
|
|
69
|
+
- name: block-env-files
|
|
70
|
+
match:
|
|
71
|
+
method: tools/call
|
|
72
|
+
tool: "*"
|
|
73
|
+
arguments:
|
|
74
|
+
_any_value:
|
|
75
|
+
regex: "/\\.env($|\\.)"
|
|
76
|
+
action: deny
|
|
77
|
+
message: "Blocked: access to .env files"
|
|
78
|
+
|
|
79
|
+
- name: block-credentials
|
|
80
|
+
match:
|
|
81
|
+
method: tools/call
|
|
82
|
+
tool: "*"
|
|
83
|
+
arguments:
|
|
84
|
+
_any_value:
|
|
85
|
+
regex: "(\\.aws/|\\.npmrc|\\.docker/config\\.json|\\.kube/config|\\.gnupg/|\\.netrc|\\.pgpass)"
|
|
86
|
+
action: deny
|
|
87
|
+
message: "Blocked: access to credential files"
|
|
88
|
+
|
|
89
|
+
- name: block-browser-data
|
|
90
|
+
match:
|
|
91
|
+
method: tools/call
|
|
92
|
+
tool: "*"
|
|
93
|
+
arguments:
|
|
94
|
+
_any_value:
|
|
95
|
+
regex: "(Chrome|Firefox|Safari|Brave|Edge)/(Default|Profile|Cookies|Login Data|Web Data)"
|
|
96
|
+
action: deny
|
|
97
|
+
message: "Blocked: access to browser data"
|
|
98
|
+
|
|
99
|
+
- name: block-password-managers
|
|
100
|
+
match:
|
|
101
|
+
method: tools/call
|
|
102
|
+
tool: "*"
|
|
103
|
+
arguments:
|
|
104
|
+
_any_value:
|
|
105
|
+
regex: "(1Password|KeePass|LastPass|Bitwarden|keychain-db)"
|
|
106
|
+
action: deny
|
|
107
|
+
message: "Blocked: access to password manager data"
|
|
108
|
+
|
|
109
|
+
# === DANGEROUS COMMANDS ===
|
|
110
|
+
- name: block-destructive-commands
|
|
111
|
+
match:
|
|
112
|
+
method: tools/call
|
|
113
|
+
tool: "*"
|
|
114
|
+
arguments:
|
|
115
|
+
_any_value:
|
|
116
|
+
regex: "(rm\\s+-r|rm\\s+-f|rmdir\\s+/|mkfs|dd\\s+if=|format\\s+[A-Z]:|chmod\\s+777|chown\\s+-R)"
|
|
117
|
+
action: deny
|
|
118
|
+
message: "Blocked: destructive command"
|
|
119
|
+
|
|
120
|
+
- name: block-pipe-to-shell
|
|
121
|
+
match:
|
|
122
|
+
method: tools/call
|
|
123
|
+
tool: "*"
|
|
124
|
+
arguments:
|
|
125
|
+
_any_value:
|
|
126
|
+
regex: "(curl|wget|fetch|http).*\\|.*(bash|sh|zsh|python|node|ruby|perl)"
|
|
127
|
+
action: deny
|
|
128
|
+
message: "Blocked: piping remote content to shell"
|
|
129
|
+
|
|
130
|
+
- name: block-reverse-shells
|
|
131
|
+
match:
|
|
132
|
+
method: tools/call
|
|
133
|
+
tool: "*"
|
|
134
|
+
arguments:
|
|
135
|
+
_any_value:
|
|
136
|
+
regex: "(nc\\s+-[le]|/dev/tcp/|bash\\s+-i\\s+>&|mkfifo|socat|telnet.*\\|.*sh)"
|
|
137
|
+
action: deny
|
|
138
|
+
message: "Blocked: potential reverse shell"
|
|
139
|
+
|
|
140
|
+
- name: block-network-exfiltration
|
|
141
|
+
match:
|
|
142
|
+
method: tools/call
|
|
143
|
+
tool: "*"
|
|
144
|
+
arguments:
|
|
145
|
+
_any_value:
|
|
146
|
+
regex: "(curl|wget|nc|ncat)\\s+.*(-d|--data|--upload-file|<)"
|
|
147
|
+
action: deny
|
|
148
|
+
message: "Blocked: potential data exfiltration"
|
|
149
|
+
|
|
150
|
+
- name: block-process-manipulation
|
|
151
|
+
match:
|
|
152
|
+
method: tools/call
|
|
153
|
+
tool: "*"
|
|
154
|
+
arguments:
|
|
155
|
+
_any_value:
|
|
156
|
+
regex: "(kill\\s+-9|killall|pkill|nohup|disown|setsid)"
|
|
157
|
+
action: deny
|
|
158
|
+
message: "Blocked: process manipulation"
|
|
159
|
+
|
|
160
|
+
- name: block-system-modification
|
|
161
|
+
match:
|
|
162
|
+
method: tools/call
|
|
163
|
+
tool: "*"
|
|
164
|
+
arguments:
|
|
165
|
+
_any_value:
|
|
166
|
+
regex: "(crontab|at\\s+|systemctl|launchctl|schtasks)"
|
|
167
|
+
action: deny
|
|
168
|
+
message: "Blocked: system modification"
|
|
169
|
+
|
|
170
|
+
# === SECRET LEAKAGE ===
|
|
171
|
+
- name: block-secret-leakage
|
|
172
|
+
match:
|
|
173
|
+
method: tools/call
|
|
174
|
+
tool: "*"
|
|
175
|
+
arguments:
|
|
176
|
+
_any_value:
|
|
177
|
+
secrets: true
|
|
178
|
+
action: deny
|
|
179
|
+
message: "Blocked: detected secret/API key in tool arguments"
|
|
180
|
+
|
|
181
|
+
# === PROTOCOL SAFETY ===
|
|
182
|
+
- name: allow-initialize
|
|
183
|
+
match:
|
|
184
|
+
method: initialize
|
|
185
|
+
action: allow
|
|
186
|
+
|
|
187
|
+
- name: allow-tools-list
|
|
188
|
+
match:
|
|
189
|
+
method: tools/list
|
|
190
|
+
action: allow
|
|
191
|
+
|
|
192
|
+
- name: allow-notifications
|
|
193
|
+
match:
|
|
194
|
+
method: "notifications/*"
|
|
195
|
+
action: allow
|
|
196
|
+
|
|
197
|
+
# Default: deny everything else (set in settings above)
|
|
198
|
+
|
|
199
|
+
secrets:
|
|
200
|
+
patterns:
|
|
201
|
+
- name: aws-access-key
|
|
202
|
+
regex: "AKIA[0-9A-Z]{16}"
|
|
203
|
+
- name: aws-secret-key
|
|
204
|
+
regex: "[A-Za-z0-9/+=]{40}"
|
|
205
|
+
entropy_threshold: 4.5
|
|
206
|
+
- name: github-token
|
|
207
|
+
regex: "(gh[ps]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9_]{22,})"
|
|
208
|
+
- name: openai-key
|
|
209
|
+
regex: "sk-[A-Za-z0-9]{20,}"
|
|
210
|
+
- name: anthropic-key
|
|
211
|
+
regex: "sk-ant-[A-Za-z0-9-]{20,}"
|
|
212
|
+
- name: stripe-key
|
|
213
|
+
regex: "(sk|pk|rk)_(test|live)_[A-Za-z0-9]{24,}"
|
|
214
|
+
- name: private-key-header
|
|
215
|
+
regex: "-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----"
|
|
216
|
+
- name: jwt-token
|
|
217
|
+
regex: "eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}"
|
|
218
|
+
- name: slack-token
|
|
219
|
+
regex: "xox[bpoas]-[A-Za-z0-9-]+"
|
|
220
|
+
- name: database-url
|
|
221
|
+
regex: "(postgres|mysql|mongodb|redis)://[^\\s]+"
|
|
222
|
+
- name: gcp-key
|
|
223
|
+
regex: "AIza[0-9A-Za-z_-]{35}"
|
|
224
|
+
- name: azure-key
|
|
225
|
+
regex: "[A-Za-z0-9+/]{86}=="
|
|
226
|
+
entropy_threshold: 4.5
|