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.
Files changed (51) hide show
  1. endpointsweep-0.1.0/LICENSE +21 -0
  2. endpointsweep-0.1.0/PKG-INFO +365 -0
  3. endpointsweep-0.1.0/README.md +340 -0
  4. endpointsweep-0.1.0/collectors/__init__.py +6 -0
  5. endpointsweep-0.1.0/collectors/endpointsweep_collect.bash +619 -0
  6. endpointsweep-0.1.0/collectors/endpointsweep_collect.ps1 +654 -0
  7. endpointsweep-0.1.0/collectors/endpointsweep_collect.sh +686 -0
  8. endpointsweep-0.1.0/endpointsweep/__init__.py +13 -0
  9. endpointsweep-0.1.0/endpointsweep/checks/__init__.py +28 -0
  10. endpointsweep-0.1.0/endpointsweep/checks/caps.py +277 -0
  11. endpointsweep-0.1.0/endpointsweep/checks/fleet.py +160 -0
  12. endpointsweep-0.1.0/endpointsweep/checks/hygiene.py +230 -0
  13. endpointsweep-0.1.0/endpointsweep/checks/injection.py +152 -0
  14. endpointsweep-0.1.0/endpointsweep/checks/registry.py +213 -0
  15. endpointsweep-0.1.0/endpointsweep/checks/supplychain.py +227 -0
  16. endpointsweep-0.1.0/endpointsweep/cli.py +391 -0
  17. endpointsweep-0.1.0/endpointsweep/data/known_packages.json +66 -0
  18. endpointsweep-0.1.0/endpointsweep/matchers.py +285 -0
  19. endpointsweep-0.1.0/endpointsweep/merge.py +266 -0
  20. endpointsweep-0.1.0/endpointsweep/parsers/__init__.py +110 -0
  21. endpointsweep-0.1.0/endpointsweep/parsers/base.py +227 -0
  22. endpointsweep-0.1.0/endpointsweep/parsers/claude_desktop.py +38 -0
  23. endpointsweep-0.1.0/endpointsweep/parsers/cursor.py +26 -0
  24. endpointsweep-0.1.0/endpointsweep/parsers/generic_mcp.py +31 -0
  25. endpointsweep-0.1.0/endpointsweep/parsers/vscode.py +71 -0
  26. endpointsweep-0.1.0/endpointsweep/report/__init__.py +17 -0
  27. endpointsweep-0.1.0/endpointsweep/report/html.py +179 -0
  28. endpointsweep-0.1.0/endpointsweep/report/markdown.py +400 -0
  29. endpointsweep-0.1.0/endpointsweep/report/sarif.py +183 -0
  30. endpointsweep-0.1.0/endpointsweep/schema.py +451 -0
  31. endpointsweep-0.1.0/endpointsweep/scoring.py +120 -0
  32. endpointsweep-0.1.0/endpointsweep.egg-info/PKG-INFO +365 -0
  33. endpointsweep-0.1.0/endpointsweep.egg-info/SOURCES.txt +49 -0
  34. endpointsweep-0.1.0/endpointsweep.egg-info/dependency_links.txt +1 -0
  35. endpointsweep-0.1.0/endpointsweep.egg-info/entry_points.txt +3 -0
  36. endpointsweep-0.1.0/endpointsweep.egg-info/requires.txt +8 -0
  37. endpointsweep-0.1.0/endpointsweep.egg-info/top_level.txt +1 -0
  38. endpointsweep-0.1.0/pyproject.toml +69 -0
  39. endpointsweep-0.1.0/setup.cfg +4 -0
  40. endpointsweep-0.1.0/tests/test_checks_caps.py +140 -0
  41. endpointsweep-0.1.0/tests/test_checks_hygiene.py +96 -0
  42. endpointsweep-0.1.0/tests/test_checks_injection.py +76 -0
  43. endpointsweep-0.1.0/tests/test_checks_supplychain.py +79 -0
  44. endpointsweep-0.1.0/tests/test_cli.py +193 -0
  45. endpointsweep-0.1.0/tests/test_collectors.py +380 -0
  46. endpointsweep-0.1.0/tests/test_docs.py +83 -0
  47. endpointsweep-0.1.0/tests/test_fleet.py +155 -0
  48. endpointsweep-0.1.0/tests/test_parsers.py +120 -0
  49. endpointsweep-0.1.0/tests/test_reports.py +167 -0
  50. endpointsweep-0.1.0/tests/test_sarif_schema.py +54 -0
  51. 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: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
36
+ [![python: 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](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.