endpointsweep 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.
- endpointsweep-0.1.0/LICENSE +21 -0
- endpointsweep-0.1.0/PKG-INFO +365 -0
- endpointsweep-0.1.0/README.md +340 -0
- endpointsweep-0.1.0/collectors/__init__.py +6 -0
- endpointsweep-0.1.0/collectors/endpointsweep_collect.bash +619 -0
- endpointsweep-0.1.0/collectors/endpointsweep_collect.ps1 +654 -0
- endpointsweep-0.1.0/collectors/endpointsweep_collect.sh +686 -0
- endpointsweep-0.1.0/endpointsweep/__init__.py +13 -0
- endpointsweep-0.1.0/endpointsweep/checks/__init__.py +28 -0
- endpointsweep-0.1.0/endpointsweep/checks/caps.py +277 -0
- endpointsweep-0.1.0/endpointsweep/checks/fleet.py +160 -0
- endpointsweep-0.1.0/endpointsweep/checks/hygiene.py +230 -0
- endpointsweep-0.1.0/endpointsweep/checks/injection.py +152 -0
- endpointsweep-0.1.0/endpointsweep/checks/registry.py +213 -0
- endpointsweep-0.1.0/endpointsweep/checks/supplychain.py +227 -0
- endpointsweep-0.1.0/endpointsweep/cli.py +391 -0
- endpointsweep-0.1.0/endpointsweep/data/known_packages.json +66 -0
- endpointsweep-0.1.0/endpointsweep/matchers.py +285 -0
- endpointsweep-0.1.0/endpointsweep/merge.py +266 -0
- endpointsweep-0.1.0/endpointsweep/parsers/__init__.py +110 -0
- endpointsweep-0.1.0/endpointsweep/parsers/base.py +227 -0
- endpointsweep-0.1.0/endpointsweep/parsers/claude_desktop.py +38 -0
- endpointsweep-0.1.0/endpointsweep/parsers/cursor.py +26 -0
- endpointsweep-0.1.0/endpointsweep/parsers/generic_mcp.py +31 -0
- endpointsweep-0.1.0/endpointsweep/parsers/vscode.py +71 -0
- endpointsweep-0.1.0/endpointsweep/report/__init__.py +17 -0
- endpointsweep-0.1.0/endpointsweep/report/html.py +179 -0
- endpointsweep-0.1.0/endpointsweep/report/markdown.py +400 -0
- endpointsweep-0.1.0/endpointsweep/report/sarif.py +183 -0
- endpointsweep-0.1.0/endpointsweep/schema.py +451 -0
- endpointsweep-0.1.0/endpointsweep/scoring.py +120 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/PKG-INFO +365 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/SOURCES.txt +49 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/dependency_links.txt +1 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/entry_points.txt +3 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/requires.txt +8 -0
- endpointsweep-0.1.0/endpointsweep.egg-info/top_level.txt +1 -0
- endpointsweep-0.1.0/pyproject.toml +69 -0
- endpointsweep-0.1.0/setup.cfg +4 -0
- endpointsweep-0.1.0/tests/test_checks_caps.py +140 -0
- endpointsweep-0.1.0/tests/test_checks_hygiene.py +96 -0
- endpointsweep-0.1.0/tests/test_checks_injection.py +76 -0
- endpointsweep-0.1.0/tests/test_checks_supplychain.py +79 -0
- endpointsweep-0.1.0/tests/test_cli.py +193 -0
- endpointsweep-0.1.0/tests/test_collectors.py +380 -0
- endpointsweep-0.1.0/tests/test_docs.py +83 -0
- endpointsweep-0.1.0/tests/test_fleet.py +155 -0
- endpointsweep-0.1.0/tests/test_parsers.py +120 -0
- endpointsweep-0.1.0/tests/test_reports.py +167 -0
- endpointsweep-0.1.0/tests/test_sarif_schema.py +54 -0
- endpointsweep-0.1.0/tests/test_schema.py +101 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EndpointSweep authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: endpointsweep
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fleet-scale discovery and audit of MCP servers and agentic AI tooling across an endpoint fleet.
|
|
5
|
+
Author: EndpointSweep authors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/endpointsweep/endpointsweep
|
|
8
|
+
Keywords: mcp,agentic-ai,security,endpoint,fleet,shadow-ai,audit
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Provides-Extra: rich
|
|
19
|
+
Requires-Dist: rich>=13.0; extra == "rich"
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
22
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
23
|
+
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# EndpointSweep
|
|
27
|
+
|
|
28
|
+
**Find every MCP server and AI agent on your fleet — before your attacker does.**
|
|
29
|
+
|
|
30
|
+
Nmap + osquery for the agentic AI era: discover every MCP server, agentic CLI and
|
|
31
|
+
AI integration running across an endpoint fleet, audit each against a published
|
|
32
|
+
risk rubric, and aggregate the findings into one report — built to run under real
|
|
33
|
+
EDR/MDM deployment constraints.
|
|
34
|
+
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](pyproject.toml)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Why this exists
|
|
41
|
+
|
|
42
|
+
The per-machine MCP scanner niche is crowded and good: [MCP-Scan][mcp-scan],
|
|
43
|
+
[mcp-audit][mcp-audit], [MCTS][mcts] and others all answer *"is this laptop's MCP
|
|
44
|
+
configuration safe?"* well.
|
|
45
|
+
|
|
46
|
+
Nobody answers the enterprise question:
|
|
47
|
+
|
|
48
|
+
> **What MCP servers and agentic AI tools exist across my 20,000 endpoints, what
|
|
49
|
+
> can they touch, and which ones violate policy?**
|
|
50
|
+
|
|
51
|
+
That question needs a different shape of tool: tiny collectors that survive real
|
|
52
|
+
fleet-deployment constraints, and a central analyzer that can compare hosts to
|
|
53
|
+
each other. **Run mcp-audit on one box; run EndpointSweep on ten thousand.**
|
|
54
|
+
|
|
55
|
+
Three findings in this tool cannot exist on a single machine at all:
|
|
56
|
+
|
|
57
|
+
- **ES-901** — one server name resolving to different commands across the fleet.
|
|
58
|
+
Every host looks internally consistent; the divergence is the finding.
|
|
59
|
+
- **ES-902** — a server on 0.4% of the fleet and on no approved-software list.
|
|
60
|
+
Rarity is only measurable against a denominator.
|
|
61
|
+
- **ES-903** — the census: what is actually deployed, ranked by prevalence.
|
|
62
|
+
|
|
63
|
+
[mcp-scan]: https://github.com/invariantlabs-ai/mcp-scan
|
|
64
|
+
[mcp-audit]: https://pypi.org/project/mcp-audit-scanner/
|
|
65
|
+
[mcts]: https://github.com/mcp-audit/mcts
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Install
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
git clone https://github.com/endpointsweep/endpointsweep
|
|
73
|
+
cd endpointsweep
|
|
74
|
+
pip install -e .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Python 3.10+, standard library only. The collectors have no dependencies at all.
|
|
78
|
+
|
|
79
|
+
This installs two identical entry points: `endpointsweep` and the short alias
|
|
80
|
+
`esweep`. The rest of this README uses the long form; use whichever you prefer.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
### One machine (the on-ramp)
|
|
87
|
+
|
|
88
|
+
`endpointsweep scan` runs this machine's collector and analyses the result — same
|
|
89
|
+
output as below, for your own laptop:
|
|
90
|
+
|
|
91
|
+
```console
|
|
92
|
+
$ endpointsweep analyze testdata/hosts/ws-win-1175.json
|
|
93
|
+
# EndpointSweep host report — `ws-win-1175`
|
|
94
|
+
|
|
95
|
+
**Risk score:** 82.5/100 (CRITICAL) · **Max severity:** CRITICAL · **Findings:** 8
|
|
96
|
+
|
|
97
|
+
**CRITICAL** 1 · **HIGH** 3 · **MEDIUM** 0 · **LOW** 0 · **INFO** 4
|
|
98
|
+
...
|
|
99
|
+
### CRITICAL (1)
|
|
100
|
+
|
|
101
|
+
#### ES-201 — Imperative-instruction pattern in MCP tool description (tool poisoning)
|
|
102
|
+
|
|
103
|
+
**Severity:** CRITICAL · **Vector:** 4 (Local MCP servers)
|
|
104
|
+
|
|
105
|
+
- **Subject:** `notes:read_file`
|
|
106
|
+
- **Detail:** tool description matches 4 injection pattern(s): fake-system-tag,
|
|
107
|
+
conceal-from-user, mandatory-tool-call, tool-ordering-hijack
|
|
108
|
+
- **Location:** `C:\Users\morgan\.cursor\mcp.json`
|
|
109
|
+
- **OWASP LLM Top 10:** LLM01: Prompt Injection, LLM04: Data and Model Poisoning
|
|
110
|
+
- **MITRE ATLAS:** AML.T0051: LLM Prompt Injection, AML.T0053: LLM Plugin Compromise
|
|
111
|
+
- **Fix:** Treat the server as compromised until proven otherwise: disable it,
|
|
112
|
+
diff the tool descriptions against the upstream source, and pin the package version.
|
|
113
|
+
|
|
114
|
+
$ echo $?
|
|
115
|
+
1
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### A fleet
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
# 1. Push a collector with your MDM/EDR (see deploy/) and collect the JSON.
|
|
122
|
+
# 2. Merge and report.
|
|
123
|
+
endpointsweep merge collected/ -o fleet.json
|
|
124
|
+
endpointsweep report fleet.json -o fleet.md
|
|
125
|
+
endpointsweep report fleet.json -f sarif -o fleet.sarif # into your scanning pipeline
|
|
126
|
+
endpointsweep report fleet.json -f html -o fleet.html # for the people who want a PDF
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Try it on the synthetic fleet
|
|
130
|
+
|
|
131
|
+
The repo ships 28 synthetic hosts (all invented — no real fleet data, ever):
|
|
132
|
+
|
|
133
|
+
```console
|
|
134
|
+
$ endpointsweep report testdata/hosts --drilldown 0 | head -20
|
|
135
|
+
# EndpointSweep fleet report
|
|
136
|
+
|
|
137
|
+
**Generated:** 2026-09-14T04:00:00+00:00 · **EndpointSweep:** v0.1.0 · **Hosts:** 28
|
|
138
|
+
|
|
139
|
+
**Fleet risk score:** 38.4/100 (MODERATE)
|
|
140
|
+
|
|
141
|
+
## Executive summary
|
|
142
|
+
|
|
143
|
+
**CRITICAL** 3 · **HIGH** 29 · **MEDIUM** 23 · **LOW** 0 · **INFO** 74
|
|
144
|
+
|
|
145
|
+
| Metric | Value |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Hosts analysed | 28 |
|
|
148
|
+
| Hosts with at least one MCP server | 22 |
|
|
149
|
+
| Hosts with an agentic CLI | 21 |
|
|
150
|
+
| Hosts with a local model runtime | 5 |
|
|
151
|
+
| Total findings | 129 |
|
|
152
|
+
| Fleet-level findings | 10 |
|
|
153
|
+
| Median host score | 13.3 |
|
|
154
|
+
| p95 host score | 80.9 |
|
|
155
|
+
| Hosts by band | LOW 14 · MODERATE 4 · ELEVATED 5 · CRITICAL 5 |
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The census section is the part people actually read (excerpt, aligned for
|
|
159
|
+
legibility — the real table is markdown):
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
### MCP servers by prevalence
|
|
163
|
+
|
|
164
|
+
| Server | Hosts | % fleet | Distinct invocations |
|
|
165
|
+
|---------------------|-------|---------|----------------------|
|
|
166
|
+
| memory | 15 | 53.6% | 1 |
|
|
167
|
+
| sequential-thinking | 13 | 46.4% | 1 |
|
|
168
|
+
| time | 9 | 32.1% | 1 |
|
|
169
|
+
| filesystem | 8 | 28.6% | 1 |
|
|
170
|
+
| internal-docs | 6 | 21.4% | 1 |
|
|
171
|
+
| github | 4 | 14.3% | 1 |
|
|
172
|
+
| internal-tools | 4 | 14.3% | 3 | <- ES-901
|
|
173
|
+
| … |
|
|
174
|
+
| desktop-commander | 1 | 3.6% | 1 | <- ES-902
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## How it works
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
endpoint central
|
|
183
|
+
┌──────────────────────────────┐ ┌───────────────────────────────┐
|
|
184
|
+
│ endpointsweep_collect.sh/.bash │ │ endpointsweep analyze │
|
|
185
|
+
│ endpointsweep_collect.ps1 │ JSON │ parsers → checks → score │
|
|
186
|
+
│ │ ───► │ │
|
|
187
|
+
│ · MCP client configs │ │ endpointsweep merge │
|
|
188
|
+
│ · agentic CLIs, IDE plugins │ │ N hosts → fleet model │
|
|
189
|
+
│ · model runtimes, manifests │ │ → ES-9xx fleet checks │
|
|
190
|
+
│ · credential-shaped NAMES │ │ │
|
|
191
|
+
│ │ │ endpointsweep report │
|
|
192
|
+
│ no deps · root-tolerant │ │ Markdown · SARIF · HTML │
|
|
193
|
+
└──────────────────────────────┘ └───────────────────────────────┘
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Collectors** are tiny and constraint-compliant, because that is the part that
|
|
197
|
+
has to survive an MDM console. **Everything else is central**, because that is
|
|
198
|
+
where it can be tested, reviewed, and changed without touching 20,000 endpoints.
|
|
199
|
+
|
|
200
|
+
### The collector contract
|
|
201
|
+
|
|
202
|
+
```sh
|
|
203
|
+
endpointsweep_collect.sh [OUTPUT_JSON_PATH] # macOS — POSIX sh, .sh extension
|
|
204
|
+
endpointsweep_collect.bash [OUTPUT_JSON_PATH] # Linux
|
|
205
|
+
endpointsweep_collect.ps1 [OUTPUT_JSON_PATH] # Windows — PowerShell 5.1
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- With a path: JSON goes to the file, the summary line goes to **stdout**.
|
|
209
|
+
- Without one: JSON goes to **stdout**, the summary line goes to **stderr**.
|
|
210
|
+
- Exit `0` = nothing flagged, `1` = something flagged, `2` = the collector failed.
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
ENDPOINTSWEEP|ws-mac-1042|9|HIGH
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
One line, under 500 characters, so it survives a console that truncates stdout —
|
|
217
|
+
and an exit code, for the consoles that only trust exit codes. See
|
|
218
|
+
[deploy/](deploy/) for Endpoint Central, Jamf, Intune and ssh recipes.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## The red line
|
|
223
|
+
|
|
224
|
+
**EndpointSweep reports variable NAMES and file PATHS. It never reports a value.**
|
|
225
|
+
|
|
226
|
+
This is enforced in four places, not asserted in a README:
|
|
227
|
+
|
|
228
|
+
1. **The collectors** cut each rc-file line at the first `=` before the name
|
|
229
|
+
reaches a pipeline, and pass every config file through an embedded
|
|
230
|
+
JSONC-aware redactor that replaces the value of any `env`/`headers`/
|
|
231
|
+
credential-shaped key with `"[redacted]"` before it is written.
|
|
232
|
+
2. **The parsers** drop the `env` mapping entirely at the boundary, and strip
|
|
233
|
+
credential-shaped segments out of remote server URLs.
|
|
234
|
+
3. **The schema** has no field that can hold a value — `MCPServer.env_var_names`
|
|
235
|
+
exists, `MCPServer.env` does not — and `to_json()` refuses to serialise any
|
|
236
|
+
structure containing a forbidden key.
|
|
237
|
+
4. **The tests** prove it: every schema dataclass is inspected for value-bearing
|
|
238
|
+
fields, and the Linux collector is executed against a fake home seeded with
|
|
239
|
+
real-looking secrets, which must not appear in its output.
|
|
240
|
+
|
|
241
|
+
The collectors also never execute a binary from a user-writable path while
|
|
242
|
+
running as root — a fleet script that runs `~/.local/bin/claude --version` as
|
|
243
|
+
root is a privilege-escalation primitive, not an inventory tool.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## The check catalog
|
|
248
|
+
|
|
249
|
+
17 checks, each carrying an ID, severity, vector, OWASP LLM Top 10 and MITRE
|
|
250
|
+
ATLAS mapping, and fix guidance. Full detail in [docs/checks.md](docs/checks.md).
|
|
251
|
+
|
|
252
|
+
```console
|
|
253
|
+
$ endpointsweep checks
|
|
254
|
+
ES-101 HIGH V4 host MCP server has local command-execution capability
|
|
255
|
+
ES-102 HIGH V4 host Filesystem MCP server rooted at a filesystem or home directory
|
|
256
|
+
ES-103 MEDIUM V4 host Network-egress MCP server with unrestricted host scope
|
|
257
|
+
ES-104 HIGH V4 host MCP server binary runs from a user- or world-writable path
|
|
258
|
+
ES-105 MEDIUM V4 host MCP server declared in an elevated (root/SYSTEM) scope
|
|
259
|
+
ES-201 CRITICAL V4 host Imperative-instruction pattern in MCP tool description (tool poisoning)
|
|
260
|
+
ES-202 MEDIUM V4 host Anomalous MCP tool description length, entropy or character mix
|
|
261
|
+
ES-301 HIGH V7 host MCP server launched from an unpinned package version
|
|
262
|
+
ES-302 MEDIUM V7 host MCP server package name is a near-miss of a known server (typosquat)
|
|
263
|
+
ES-303 MEDIUM V7 host MCP server package is very new or has a single maintainer [--online]
|
|
264
|
+
ES-401 HIGH V8 host Credential-shaped variable names embedded in an MCP server config
|
|
265
|
+
ES-402 MEDIUM V8 host Credential-shaped variable names in shell rc or .env files
|
|
266
|
+
ES-403 LOW V5 host Local model runtime listening on a non-loopback interface
|
|
267
|
+
ES-404 INFO V3 host Shadow-AI inventory (census signal, not an alert)
|
|
268
|
+
ES-901 HIGH V4 fleet Same MCP server name resolves to different commands across the fleet
|
|
269
|
+
ES-902 MEDIUM V4 fleet Long-tail MCP server installed on a small fraction of the fleet
|
|
270
|
+
ES-903 INFO V3 fleet Fleet shadow-AI census
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Everything is deterministic and offline by default. Exactly one check (ES-303)
|
|
274
|
+
makes a network request, and only behind `--online`.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## The rubric
|
|
279
|
+
|
|
280
|
+
[docs/rubric.md](docs/rubric.md) is the durable part of this project: a
|
|
281
|
+
tool-agnostic way to describe enterprise AI exposure that outlives the MCP spec.
|
|
282
|
+
|
|
283
|
+
- **Eight vectors** — browser AI modes, browser AI extensions, agentic AI, local
|
|
284
|
+
MCP servers, local model runtimes, IDE AI plugins, AI libraries, direct
|
|
285
|
+
API-key integrations.
|
|
286
|
+
- **Six capability axes** — execution, filesystem reach, network reach,
|
|
287
|
+
credential exposure, privilege, provenance & control.
|
|
288
|
+
- **A scoring formula you can reproduce by hand**, that saturates, with honest
|
|
289
|
+
coverage reporting: vectors EndpointSweep does not yet collect are shown as gaps,
|
|
290
|
+
never as clean.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Commands
|
|
295
|
+
|
|
296
|
+
| Command | What it does |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `endpointsweep scan` | Run this machine's collector, then analyse it |
|
|
299
|
+
| `endpointsweep analyze HOST.json...` | Analyse collector output, one report per host |
|
|
300
|
+
| `endpointsweep merge HOSTS/ -o fleet.json` | N hosts → one scored fleet model |
|
|
301
|
+
| `endpointsweep report fleet.json` | Markdown (default), `-f html\|sarif\|json` |
|
|
302
|
+
| `endpointsweep checks` | Print the catalog (`-f json` for machines) |
|
|
303
|
+
| `endpointsweep collector --os macos --print` | Emit a collector for deployment |
|
|
304
|
+
|
|
305
|
+
`esweep` is a drop-in alias for `endpointsweep` on every command above.
|
|
306
|
+
|
|
307
|
+
Useful flags: `--fail-on {none,info,low,medium,high,critical}` (default `high`)
|
|
308
|
+
for CI exit codes, `--managed-software FILE` to suppress expected long-tail
|
|
309
|
+
installs, `--rare-threshold` to tune ES-902, `--online` to enable ES-303.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Project layout
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
collectors/ three self-contained endpoint scripts (the deployable part)
|
|
317
|
+
endpointsweep/ parsers → checks → scoring → merge → report
|
|
318
|
+
checks/ one module per family; registry pattern; ES-1xx … ES-9xx
|
|
319
|
+
parsers/ one module per client config shape
|
|
320
|
+
report/ markdown, sarif, html
|
|
321
|
+
plugins/ optional: fold mcp-scan / mcp-audit output into the fleet report
|
|
322
|
+
testdata/ 28 synthetic hosts, config fixtures, golden expectations, SARIF schema
|
|
323
|
+
deploy/ Endpoint Central, Jamf, Intune, ssh recipes
|
|
324
|
+
docs/ rubric.md (the IP), checks.md (the catalog)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Development
|
|
330
|
+
|
|
331
|
+
```sh
|
|
332
|
+
pip install -e ".[dev]"
|
|
333
|
+
pytest # 165 tests, incl. live collector runs and SARIF schema validation
|
|
334
|
+
ruff check .
|
|
335
|
+
python3 testdata/generate_fleet.py # regenerate the synthetic fleet
|
|
336
|
+
python3 testdata/generate_golden.py # regenerate golden expectations, then read the diff
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Adding a check: [docs/checks.md § Adding a check](docs/checks.md#adding-a-check).
|
|
340
|
+
`tests/test_docs.py` fails the build if a check is not documented.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Scope
|
|
345
|
+
|
|
346
|
+
**In scope:** discovery, audit, aggregation, reporting.
|
|
347
|
+
|
|
348
|
+
**Out of scope, deliberately:** runtime proxying and traffic inspection (MCP-Scan
|
|
349
|
+
owns that lane); LLM-based semantic analysis of tool descriptions (checks stay
|
|
350
|
+
deterministic); remediation and enforcement (report first, enforce later); and
|
|
351
|
+
any transmission of secret values, file contents or user documents.
|
|
352
|
+
|
|
353
|
+
## Credits
|
|
354
|
+
|
|
355
|
+
EndpointSweep stands on work done by others in the open: [MCP-Scan][mcp-scan] for
|
|
356
|
+
naming tool poisoning and rug pulls, [mcp-audit][mcp-audit] for the OWASP MCP
|
|
357
|
+
mapping, and [MCTS][mcts] for live tool discovery. They solve the single-machine
|
|
358
|
+
problem well — `plugins/external_scanners.py` will fold their output into an
|
|
359
|
+
EndpointSweep fleet report rather than duplicate it.
|
|
360
|
+
|
|
361
|
+
Mappings reference the OWASP LLM Top 10 (2025) and MITRE ATLAS.
|
|
362
|
+
|
|
363
|
+
## License
|
|
364
|
+
|
|
365
|
+
MIT. All test data in this repository is synthetic.
|