cipher-mcp-scan 0.1.0__tar.gz
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.
- cipher_mcp_scan-0.1.0/PKG-INFO +367 -0
- cipher_mcp_scan-0.1.0/README.md +357 -0
- cipher_mcp_scan-0.1.0/checks/__init__.py +22 -0
- cipher_mcp_scan-0.1.0/checks/authentication/__init__.py +11 -0
- cipher_mcp_scan-0.1.0/checks/authentication/auth_check.py +772 -0
- cipher_mcp_scan-0.1.0/checks/authentication/self_test.py +187 -0
- cipher_mcp_scan-0.1.0/checks/cve_lookup/__init__.py +3 -0
- cipher_mcp_scan-0.1.0/checks/cve_lookup/cve_check.py +875 -0
- cipher_mcp_scan-0.1.0/checks/cve_lookup/self_test.py +263 -0
- cipher_mcp_scan-0.1.0/checks/over_privilege/__init__.py +1 -0
- cipher_mcp_scan-0.1.0/checks/over_privilege/over_privilege_check.py +757 -0
- cipher_mcp_scan-0.1.0/checks/over_privilege/self_test.py +100 -0
- cipher_mcp_scan-0.1.0/checks/typosquatting/__init__.py +3 -0
- cipher_mcp_scan-0.1.0/checks/typosquatting/self_test.py +107 -0
- cipher_mcp_scan-0.1.0/checks/typosquatting/typosquatting_check.py +668 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan/__init__.py +6 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan/cli.py +49 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan/models.py +56 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan/runner.py +125 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/PKG-INFO +367 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/SOURCES.txt +26 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/dependency_links.txt +1 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/entry_points.txt +2 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/requires.txt +1 -0
- cipher_mcp_scan-0.1.0/cipher_mcp_scan.egg-info/top_level.txt +2 -0
- cipher_mcp_scan-0.1.0/pyproject.toml +24 -0
- cipher_mcp_scan-0.1.0/setup.cfg +4 -0
- cipher_mcp_scan-0.1.0/tests/test_cipher_mcp_scan.py +14 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cipher-mcp-scan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local security scan CLI for Cipher checks
|
|
5
|
+
Author: Cipher
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: requests<3.0.0,>=2.31.0
|
|
10
|
+
|
|
11
|
+
# Cipher
|
|
12
|
+
|
|
13
|
+
Cipher is a local static-analysis scanner for security and supply-chain review. It inspects a project path and runs four focused checks:
|
|
14
|
+
|
|
15
|
+
1. Authentication
|
|
16
|
+
2. Over-Privilege
|
|
17
|
+
3. CVE Lookup
|
|
18
|
+
4. Typosquatting / Shadowing
|
|
19
|
+
|
|
20
|
+
The goal of this repository is not to guess at security problems. It is to produce high-signal findings from concrete code and manifest evidence, then present them in a format that is useful for triage.
|
|
21
|
+
|
|
22
|
+
## Installing the CLI package
|
|
23
|
+
|
|
24
|
+
This repo can also be installed as a local CLI package:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install -e .
|
|
28
|
+
cipher-scan . --fail-on high
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The package is intentionally local-path only for v0.1: it scans the checked-out repository on disk, without any Render, Ollama, or remote download dependency.
|
|
32
|
+
|
|
33
|
+
Use `--fail-on none` when you want a report-only run without a failing exit code.
|
|
34
|
+
|
|
35
|
+
### Example local usage
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cipher-scan .
|
|
39
|
+
cipher-scan . --fail-on high --format json
|
|
40
|
+
cipher-scan . --fail-on high --output cipher-scan-report.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Private repositories work the same way as any other local repo: use GitHub Actions or a local checkout, then scan the checked-out path with `cipher-scan .`.
|
|
44
|
+
|
|
45
|
+
## What This Repository Contains
|
|
46
|
+
|
|
47
|
+
At the top level, Cipher has a very small shape:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
s:\Cipher
|
|
51
|
+
├── checks/
|
|
52
|
+
├── main/
|
|
53
|
+
├── test/
|
|
54
|
+
├── run_checks.py
|
|
55
|
+
└── README.md
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The important part is the `checks/` package. Each subpackage owns one security analysis area and exposes a public `scan()` interface. `run_checks.py` is the simple combined runner that executes all four checks in order for a local project path.
|
|
59
|
+
|
|
60
|
+
## System Architecture
|
|
61
|
+
|
|
62
|
+
The overall flow is intentionally simple.
|
|
63
|
+
|
|
64
|
+
```mermaid
|
|
65
|
+
flowchart TD
|
|
66
|
+
A[User provides local project path] --> B[run_checks.py]
|
|
67
|
+
B --> C[AuthenticationCheck]
|
|
68
|
+
B --> D[OverPrivilegeCheck]
|
|
69
|
+
B --> E[CVELookupCheck]
|
|
70
|
+
B --> F[TyposquattingCheck]
|
|
71
|
+
|
|
72
|
+
C --> G[Findings]
|
|
73
|
+
D --> G
|
|
74
|
+
E --> G
|
|
75
|
+
F --> G
|
|
76
|
+
|
|
77
|
+
G --> H[Readable console summary]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The combined runner does not try to interpret findings. It simply calls each check, catches errors per check, and prints a clean summary so one failure does not stop the rest of the scan.
|
|
81
|
+
|
|
82
|
+
## Why The Architecture Looks This Way
|
|
83
|
+
|
|
84
|
+
The design is deliberately modular.
|
|
85
|
+
|
|
86
|
+
- Each check can be tested and improved independently.
|
|
87
|
+
- Each check has its own data model assumptions and heuristics.
|
|
88
|
+
- The runner remains small and stable even if one security area evolves.
|
|
89
|
+
- A failure in one analysis path does not block the others.
|
|
90
|
+
|
|
91
|
+
That separation matters because the four checks solve different problems:
|
|
92
|
+
|
|
93
|
+
- Authentication looks for missing guards on sensitive handlers.
|
|
94
|
+
- Over-Privilege looks for excessive capabilities and dangerous combinations.
|
|
95
|
+
- CVE Lookup looks for vulnerable dependencies in manifests and lockfiles.
|
|
96
|
+
- Typosquatting looks for suspicious near-matches and tool-name shadowing.
|
|
97
|
+
|
|
98
|
+
## How A Scan Works
|
|
99
|
+
|
|
100
|
+
The scan lifecycle is the same at a high level for all checks:
|
|
101
|
+
|
|
102
|
+
```mermaid
|
|
103
|
+
sequenceDiagram
|
|
104
|
+
participant U as User
|
|
105
|
+
participant R as run_checks.py
|
|
106
|
+
participant C as Check implementation
|
|
107
|
+
participant O as Output
|
|
108
|
+
|
|
109
|
+
U->>R: Provide project path
|
|
110
|
+
R->>C: scan(project_root)
|
|
111
|
+
C->>C: Discover files and build context
|
|
112
|
+
C->>C: Apply rules / heuristics
|
|
113
|
+
C->>C: Return findings
|
|
114
|
+
R->>O: Print findings and summary
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Each check follows that same pattern, but the internal analysis differs.
|
|
118
|
+
|
|
119
|
+
## Check Overview
|
|
120
|
+
|
|
121
|
+
### 1) Authentication Check
|
|
122
|
+
|
|
123
|
+
The Authentication Check scans source code for security-sensitive entry points that appear to be exposed without a clear authentication guard.
|
|
124
|
+
|
|
125
|
+
What it looks for:
|
|
126
|
+
|
|
127
|
+
- MCP-style tool handlers
|
|
128
|
+
- Route handlers that appear to do privileged work
|
|
129
|
+
- Weak secret defaults and fail-open secret checks
|
|
130
|
+
- Empty allowlists and risky CORS-style trust patterns
|
|
131
|
+
- Non-loopback service bindings without a visible auth gate
|
|
132
|
+
- Inconsistent auth enforcement across sibling routes
|
|
133
|
+
|
|
134
|
+
Architecture view:
|
|
135
|
+
|
|
136
|
+
```mermaid
|
|
137
|
+
flowchart LR
|
|
138
|
+
A[Source files] --> B[Parser / AST extraction]
|
|
139
|
+
B --> C[Auth signal detector]
|
|
140
|
+
C --> D[Implementation validator]
|
|
141
|
+
D --> E[Security scorer]
|
|
142
|
+
E --> F[Finding]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The important idea is that the module does not rely on a single string match. It combines structure, decorators, routes, imports, and auth-related evidence before emitting a finding.
|
|
146
|
+
|
|
147
|
+
### 2) Over-Privilege Check
|
|
148
|
+
|
|
149
|
+
The Over-Privilege Check looks at tool and capability declarations, especially MCP configuration, and asks a simple question: does this tool request more power than it needs?
|
|
150
|
+
|
|
151
|
+
What it looks for:
|
|
152
|
+
|
|
153
|
+
- filesystem read/write/execute capabilities
|
|
154
|
+
- network access
|
|
155
|
+
- credential access
|
|
156
|
+
- database access
|
|
157
|
+
- system or process privileges
|
|
158
|
+
- dangerous capability combinations such as data exfiltration or privilege escalation chains
|
|
159
|
+
|
|
160
|
+
Architecture view:
|
|
161
|
+
|
|
162
|
+
```mermaid
|
|
163
|
+
flowchart LR
|
|
164
|
+
A[mcp.json / capability config] --> B[Capability extractor]
|
|
165
|
+
B --> C[Dangerous combo detector]
|
|
166
|
+
C --> D[Least-privilege evaluator]
|
|
167
|
+
D --> E[Risk calculator]
|
|
168
|
+
E --> F[Finding]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This check is policy-driven. The capability taxonomy and combo table define the security meaning, while the evaluator turns those declarations into findings and severity.
|
|
172
|
+
|
|
173
|
+
### 3) CVE Lookup Check
|
|
174
|
+
|
|
175
|
+
The CVE Lookup Check is a dependency vulnerability scan for supported manifests and lockfiles.
|
|
176
|
+
|
|
177
|
+
Supported inputs:
|
|
178
|
+
|
|
179
|
+
- `requirements.txt` and `requirements-*.txt`
|
|
180
|
+
- `pyproject.toml`
|
|
181
|
+
- `package.json`
|
|
182
|
+
- `package-lock.json`
|
|
183
|
+
- `poetry.lock`
|
|
184
|
+
|
|
185
|
+
Architecture view:
|
|
186
|
+
|
|
187
|
+
```mermaid
|
|
188
|
+
flowchart LR
|
|
189
|
+
A[Dependency manifests] --> B[Dependency extractor]
|
|
190
|
+
B --> C[Version resolution / lockfile hints]
|
|
191
|
+
C --> D[OSV-compatible lookup]
|
|
192
|
+
D --> E[Cache]
|
|
193
|
+
D --> F[Finding builder]
|
|
194
|
+
E --> D
|
|
195
|
+
F --> G[Aggregated findings]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This check is designed to stay offline-safe when network lookup is unavailable. It also keeps the output low-noise by aggregating by package and merging vulnerability identifiers into a single finding when possible.
|
|
199
|
+
|
|
200
|
+
### 4) Typosquatting / Shadowing Check
|
|
201
|
+
|
|
202
|
+
The Typosquatting Check scans package names and MCP tool names for suspicious near-matches.
|
|
203
|
+
|
|
204
|
+
What it looks for:
|
|
205
|
+
|
|
206
|
+
- package names that closely resemble known popular package names
|
|
207
|
+
- MCP tool names that closely resemble known tool names
|
|
208
|
+
- duplicate tool names that can shadow one another across configs
|
|
209
|
+
|
|
210
|
+
Architecture view:
|
|
211
|
+
|
|
212
|
+
```mermaid
|
|
213
|
+
flowchart LR
|
|
214
|
+
A[Manifest and MCP names] --> B[Name extractor]
|
|
215
|
+
B --> C[Similarity detector]
|
|
216
|
+
B --> D[Shadowing detector]
|
|
217
|
+
C --> E[Finding builder]
|
|
218
|
+
D --> E
|
|
219
|
+
E --> F[Offline-safe findings]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
This check is also offline-safe. It works from a local trusted-name catalog and local project files, not from external registry queries.
|
|
223
|
+
|
|
224
|
+
## Combined Runner
|
|
225
|
+
|
|
226
|
+
`run_checks.py` is the main entry point for demo use.
|
|
227
|
+
|
|
228
|
+
What it does:
|
|
229
|
+
|
|
230
|
+
- accepts one local project path argument
|
|
231
|
+
- runs the four checks in order
|
|
232
|
+
- prints each check name and finding count
|
|
233
|
+
- prints each finding as `severity | title | file_path`
|
|
234
|
+
- catches errors per check and continues scanning the rest
|
|
235
|
+
|
|
236
|
+
Example:
|
|
237
|
+
|
|
238
|
+
```powershell
|
|
239
|
+
python run_checks.py .\test\Cipher-demo-main
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
That runner is intentionally small. It is a presentation layer, not a fifth scanner.
|
|
243
|
+
|
|
244
|
+
## Repository Map
|
|
245
|
+
|
|
246
|
+
```mermaid
|
|
247
|
+
flowchart TD
|
|
248
|
+
A[Repository root] --> B[checks/]
|
|
249
|
+
A --> C[main/]
|
|
250
|
+
A --> D[test/]
|
|
251
|
+
A --> E[run_checks.py]
|
|
252
|
+
|
|
253
|
+
B --> B1[authentication/]
|
|
254
|
+
B --> B2[over_privilege/]
|
|
255
|
+
B --> B3[cve_lookup/]
|
|
256
|
+
B --> B4[typosquatting/]
|
|
257
|
+
|
|
258
|
+
B1 --> B1a[auth_check.py]
|
|
259
|
+
B1 --> B1b[self_test.py]
|
|
260
|
+
B2 --> B2a[over_privilege_check.py]
|
|
261
|
+
B2 --> B2b[self_test.py]
|
|
262
|
+
B3 --> B3a[cve_check.py]
|
|
263
|
+
B3 --> B3b[self_test.py]
|
|
264
|
+
B4 --> B4a[typosquatting_check.py]
|
|
265
|
+
B4 --> B4b[self_test.py]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Directory Roles
|
|
269
|
+
|
|
270
|
+
- `checks/` contains the actual analysis logic.
|
|
271
|
+
- `main/` contains shared project data and support code.
|
|
272
|
+
- `test/` contains a vulnerable demo repository that the checks can scan.
|
|
273
|
+
- `run_checks.py` is the combined CLI runner.
|
|
274
|
+
|
|
275
|
+
## Output Philosophy
|
|
276
|
+
|
|
277
|
+
Cipher is designed for triage, not for maximum noise.
|
|
278
|
+
|
|
279
|
+
That means:
|
|
280
|
+
|
|
281
|
+
- findings should be explainable from the evidence shown
|
|
282
|
+
- duplicate emissions should be reduced when they do not add value
|
|
283
|
+
- remediation should point toward an obvious next action
|
|
284
|
+
- severity should reflect the strength of the signal, not just the existence of a match
|
|
285
|
+
|
|
286
|
+
In practice, a useful finding usually includes:
|
|
287
|
+
|
|
288
|
+
- severity
|
|
289
|
+
- title
|
|
290
|
+
- file path
|
|
291
|
+
- evidence
|
|
292
|
+
- remediation guidance
|
|
293
|
+
|
|
294
|
+
## Example End-to-End Scan
|
|
295
|
+
|
|
296
|
+
If you scan the bundled demo target, the runner will print a grouped summary like this:
|
|
297
|
+
|
|
298
|
+
```text
|
|
299
|
+
Scanning: S:\Cipher\test\Cipher-demo-main
|
|
300
|
+
|
|
301
|
+
== AuthenticationCheck ==
|
|
302
|
+
Findings: 4
|
|
303
|
+
- high | Missing authentication for sensitive MCP tool handler | server.py
|
|
304
|
+
|
|
305
|
+
== OverPrivilegeCheck ==
|
|
306
|
+
Findings: 6
|
|
307
|
+
- high | Dangerous combination: Data Exfiltration | S:\Cipher\test\Cipher-demo-main\mcp.json
|
|
308
|
+
|
|
309
|
+
== CVELookupCheck ==
|
|
310
|
+
Findings: 4
|
|
311
|
+
- critical | Known npm dependency vulnerability: axios | S:\Cipher\test\Cipher-demo-main\package.json
|
|
312
|
+
|
|
313
|
+
== TyposquattingCheck ==
|
|
314
|
+
Findings: 2
|
|
315
|
+
- medium | Potential package name typosquatting | S:\Cipher\test\Cipher-demo-main\package.json
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The exact findings depend on the target project, but the format stays the same.
|
|
319
|
+
|
|
320
|
+
## Working With The Individual Checks
|
|
321
|
+
|
|
322
|
+
Each check keeps the same public scan interface.
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from checks.authentication.auth_check import AuthenticationCheck
|
|
326
|
+
from checks.over_privilege.over_privilege_check import OverPrivilegeCheck
|
|
327
|
+
from checks.cve_lookup.cve_check import CVELookupCheck
|
|
328
|
+
from checks.typosquatting.typosquatting_check import TyposquattingCheck
|
|
329
|
+
|
|
330
|
+
root = r"S:\Cipher\test\Cipher-demo-main"
|
|
331
|
+
|
|
332
|
+
auth_findings = AuthenticationCheck(root).scan()
|
|
333
|
+
priv_findings = OverPrivilegeCheck(root).scan()
|
|
334
|
+
cve_findings = CVELookupCheck(root).scan()
|
|
335
|
+
typo_findings = TyposquattingCheck(root).scan()
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
That interface consistency is important because it lets the combined runner stay simple.
|
|
339
|
+
|
|
340
|
+
## Testing
|
|
341
|
+
|
|
342
|
+
The repository includes package-level self-tests for each check. The tests are designed to protect the behavior of the public scan interface and the project-specific heuristics.
|
|
343
|
+
|
|
344
|
+
Typical commands:
|
|
345
|
+
|
|
346
|
+
```powershell
|
|
347
|
+
python -m unittest checks.authentication.self_test
|
|
348
|
+
python -m unittest checks.over_privilege.self_test
|
|
349
|
+
python -m unittest checks.cve_lookup.self_test
|
|
350
|
+
python -m unittest checks.typosquatting.self_test
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Practical Notes
|
|
354
|
+
|
|
355
|
+
- The scanner works on a local path only.
|
|
356
|
+
- The CVE check prefers exact version evidence and can fall back to cache behavior when needed.
|
|
357
|
+
- The typosquatting check is offline-safe and uses a local trusted-name set.
|
|
358
|
+
- The runner is intentionally minimal so it can be used in demos without extra setup.
|
|
359
|
+
|
|
360
|
+
## Short Version
|
|
361
|
+
|
|
362
|
+
If you want the shortest mental model possible, think of Cipher like this:
|
|
363
|
+
|
|
364
|
+
1. Point it at a local project directory.
|
|
365
|
+
2. It inspects source files and manifests.
|
|
366
|
+
3. Each check produces security findings from a different angle.
|
|
367
|
+
4. The combined runner prints the result in a readable, triage-friendly summary.
|