skill-vet-cli 1.0.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.
- skill_vet_cli-1.0.0/LICENSE +21 -0
- skill_vet_cli-1.0.0/PKG-INFO +345 -0
- skill_vet_cli-1.0.0/README.md +319 -0
- skill_vet_cli-1.0.0/pyproject.toml +51 -0
- skill_vet_cli-1.0.0/setup.cfg +4 -0
- skill_vet_cli-1.0.0/src/skill_vet.py +1673 -0
- skill_vet_cli-1.0.0/src/skill_vet_cli.egg-info/PKG-INFO +345 -0
- skill_vet_cli-1.0.0/src/skill_vet_cli.egg-info/SOURCES.txt +10 -0
- skill_vet_cli-1.0.0/src/skill_vet_cli.egg-info/dependency_links.txt +1 -0
- skill_vet_cli-1.0.0/src/skill_vet_cli.egg-info/entry_points.txt +2 -0
- skill_vet_cli-1.0.0/src/skill_vet_cli.egg-info/top_level.txt +1 -0
- skill_vet_cli-1.0.0/tests/test_skill_vet.py +722 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jasveer Singh
|
|
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,345 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: skill-vet-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Vet an agent skill pack before you install it — stealing, spying and hidden sending, proven with file-and-line evidence.
|
|
5
|
+
Author: Jasveer Singh
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jasveerai88/skill-vet
|
|
8
|
+
Project-URL: Repository, https://github.com/jasveerai88/skill-vet
|
|
9
|
+
Project-URL: Issues, https://github.com/jasveerai88/skill-vet/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/jasveerai88/skill-vet/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: agent-skills,claude-code,ai-agents,security,static-analysis,cli
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<h1 align="center">skill-vet</h1>
|
|
28
|
+
|
|
29
|
+
<p align="center"><strong>Vet an agent skill before you install it — stealing, spying, hidden sending, proven with file-and-line evidence.</strong></p>
|
|
30
|
+
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img alt="tests: 44 passing" src="https://img.shields.io/badge/tests-44%20passing-brightgreen">
|
|
33
|
+
<img alt="python 3.10 | 3.11 | 3.12" src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue">
|
|
34
|
+
<img alt="version 1.0.0" src="https://img.shields.io/badge/version-1.0.0-orange">
|
|
35
|
+
<img alt="dependencies: none" src="https://img.shields.io/badge/dependencies-0-brightgreen">
|
|
36
|
+
<img alt="license: MIT" src="https://img.shields.io/badge/license-MIT-blue">
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<p align="center"><img alt="skill-vet demo: a clean pack passes, a hostile pack is BLOCKED with three danger findings" src="docs/demo.gif" width="880"></p>
|
|
40
|
+
|
|
41
|
+
A skill pack runs with your agent's permissions the moment it is
|
|
42
|
+
installed. Per-file linters check the SKILL.md's formatting; nobody
|
|
43
|
+
vets the whole directory — the frontmatter, the referenced files, and
|
|
44
|
+
above all the scripts. The marketplace numbers say why this matters:
|
|
45
|
+
Snyk's ToxicSkills audit (Feb 2026) found security flaws in 1,467
|
|
46
|
+
of 3,984 marketplace skills (36.8%) and confirmed 76 with active
|
|
47
|
+
malicious payloads on manual review. VirusTotal analysed 35,878 skills and
|
|
48
|
+
found 6,637 malicious — most of them hiding the payload in plain
|
|
49
|
+
sentences or concealment mechanics rather than obvious malware.
|
|
50
|
+
skill-vet is the local, deterministic first pass over a pack you were
|
|
51
|
+
handed, before it gets anywhere near your agent.
|
|
52
|
+
|
|
53
|
+
**Static and read-only — it executes nothing.** Vet never imports,
|
|
54
|
+
runs, compiles, or decodes anything in the pack. Every file is read
|
|
55
|
+
as text and judged as evidence. Its own source imports no network or
|
|
56
|
+
subprocess module, and the test suite proves the read-only claim
|
|
57
|
+
twice: a fixture script that would write a marker file if it ran
|
|
58
|
+
never runs, and every fixture tree comes out byte-identical after an
|
|
59
|
+
audit.
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pipx install git+https://github.com/jasveerai88/skill-vet # or: pip install git+https://github.com/jasveerai88/skill-vet
|
|
65
|
+
skill-vet vet ~/Downloads/some-skill
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
That's the whole workflow: one command, one report, an exit code you
|
|
69
|
+
can gate on — **1** = BLOCKED (do not install), **0** = CLEAN or
|
|
70
|
+
REVIEW, **2** = input error. Add `--json` for a machine-readable
|
|
71
|
+
report, `--strict` to also fail on REVIEW. From a source checkout,
|
|
72
|
+
`python3 src/skill_vet.py vet <pack>` does the same thing. Python
|
|
73
|
+
3.10+, standard library only, no dependencies.
|
|
74
|
+
|
|
75
|
+
## What it catches
|
|
76
|
+
|
|
77
|
+
A pack is DANGEROUS only if it does one of three things — and each
|
|
78
|
+
verdict needs the **combination** of evidence in the same file, both
|
|
79
|
+
halves cited. A pattern hit alone is never a danger verdict.
|
|
80
|
+
|
|
81
|
+
| Catch | What has to be true | Real example (from `examples/`) |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| **Stealing** | A script reads credential stores, SSH keys, browser profiles, or environment secrets **and** sends or copies them out | `hostile-skill/scripts/collect.py` reads an SSH key (line 12) and POSTs it (line 18) → `DANGER_STEALING` |
|
|
84
|
+
| **Spying** | A script captures screen, keyboard, microphone, camera, or browser history **and** persists or sends it, undisclosed in the docs | `hostile-skill/scripts/snoop.py` screenshots in a loop (line 12) and POSTs the shots (line 15) → `DANGER_SPYING` |
|
|
85
|
+
| **Hidden sending** | A network call whose payload or destination is concealed — an encoded payload, local file contents to an undisclosed endpoint, or any send from a pack that claims to work offline | `hostile-skill/scripts/report.py` base64-encodes a documents file (line 14) and POSTs it to an endpoint the docs never mention (line 15) → `DANGER_HIDDEN_SENDING` |
|
|
86
|
+
| **Structure errors** | SKILL.md missing or unparseable, required fields absent, referenced files that don't exist | `sloppy-skill`'s SKILL.md links `references/checklist.md`, which is not in the pack → `BROKEN_REFERENCE` |
|
|
87
|
+
| **Short of danger** | One ingredient without its combination: a credential read with no way out, an undisclosed endpoint on its own, `shell=True`, an opaque base64 blob, invisible characters | `sloppy-skill` earns 4 warnings and a REVIEW verdict — not a block — and its one honest, documented network call earns no finding at all |
|
|
88
|
+
|
|
89
|
+
Verdicts: **BLOCKED** (at least one danger finding), **REVIEW** (no
|
|
90
|
+
danger, but at least one error or warning), **CLEAN** (no errors or
|
|
91
|
+
warnings; INFO may remain). The verdict rule is printed on every
|
|
92
|
+
report. REVIEW exits 0 on purpose: REVIEW means "a human should read
|
|
93
|
+
this", and a gate that fails on warnings trains people to bypass the
|
|
94
|
+
gate. `--strict` is there for those who disagree.
|
|
95
|
+
|
|
96
|
+
[Quick start](#quick-start) · [What it catches](#what-it-catches) ·
|
|
97
|
+
[How it compares](#how-it-compares) · [Reference](#reference)
|
|
98
|
+
|
|
99
|
+
## How it compares
|
|
100
|
+
|
|
101
|
+
| | **skill-vet** | Per-file SKILL.md linter | Installing blind |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| Scope | The whole pack: frontmatter, references, inventory, every script | The SKILL.md file only | — |
|
|
104
|
+
| Danger model | Stealing / spying / hidden sending, each proven as a combination | Formatting and schema only | None |
|
|
105
|
+
| Evidence | Every finding cites file + line, both halves of a combination | Line-level style notes | — |
|
|
106
|
+
| Executes the pack? | Never — static text analysis only | No | Yes, with your agent's permissions |
|
|
107
|
+
| A lone suspicious pattern | A warning, never a block | n/a | n/a |
|
|
108
|
+
| Output | Text report + `--json`, exit codes for CI | Varies | — |
|
|
109
|
+
| Dependencies | 0 (Python 3.10+ stdlib) | Varies | — |
|
|
110
|
+
|
|
111
|
+
## Honest limits (the short version)
|
|
112
|
+
|
|
113
|
+
Static patterns are evidence, not proof. A pack that assembles its
|
|
114
|
+
behaviour at runtime, splits a danger combination across two files
|
|
115
|
+
(combinations are judged per file), or writes its social engineering
|
|
116
|
+
in plain, honest sentences can pass. A bundled binary is flagged
|
|
117
|
+
precisely because vet can say nothing about what it does when run. A
|
|
118
|
+
CLEAN verdict means *no pattern fired* — it cannot prove a pack safe,
|
|
119
|
+
and every report says so. The full limits are
|
|
120
|
+
[below](#honest-limits).
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Reference
|
|
125
|
+
|
|
126
|
+
**Contents:** [What it checks](#what-it-checks) ·
|
|
127
|
+
[Full reports: hostile](#a-hostile-pack--one-file-per-danger-test) ·
|
|
128
|
+
[sloppy](#a-sloppy-pack--careless-not-malicious) ·
|
|
129
|
+
[clean](#a-clean-pack) · [For agents](#for-agents) ·
|
|
130
|
+
[Tests](#tests) · [Honest limits](#honest-limits)
|
|
131
|
+
|
|
132
|
+
### What it checks
|
|
133
|
+
|
|
134
|
+
| Area | Rules |
|
|
135
|
+
|---|---|
|
|
136
|
+
| Structure | `MISSING_SKILL_MD` / `SKILL_MD_CASE` — no SKILL.md at the root, or under a differently-cased name. `FRONTMATTER_MISSING` / `FRONTMATTER_PARSE` — no `---` block, or a line outside the stated subset. `REQUIRED_FIELD` — `name` or `description` missing or empty. `NAME_DIR_MISMATCH` / `NAME_FORMAT` — name ≠ folder, or not a kebab-case slug. `BROAD_TOOL_GRANT` — an `allowed-tools` entry of `*`, `Tool(*)`, or bare `Bash`. |
|
|
137
|
+
| References | `BROKEN_REFERENCE` (ERROR) — a local file referenced from SKILL.md (link or backticked path) or from a script (path literal) does not exist. `REFERENCE_OUTSIDE_PACK` — a reference resolving outside the pack. |
|
|
138
|
+
| Inventory | Every file listed with kind and size. `LARGE_FILE` — over 1 MiB. `BUNDLED_BINARY` — a binary, which cannot be statically vetted at all. `SYMLINK_OUT` (INFO) — a symlink leaving the pack; its target is not scanned. `INSTALL_HOOK` — a file that runs at install time (setup.py, .pth, install scripts, package.json hooks). |
|
|
139
|
+
| Danger (BLOCKED) | `DANGER_STEALING`, `DANGER_SPYING`, `DANGER_HIDDEN_SENDING` — only on the combinations described above, both halves cited. |
|
|
140
|
+
| Short of danger | `SECRET_ACCESS` (credential read, no egress), `UNDISCLOSED_NETWORK` (endpoint the docs never mention), `DYNAMIC_ENDPOINT` (no literal URL to check), `ENCODED_PAYLOAD` (encoded payload to a *disclosed* endpoint), `DISCLOSED_CAPTURE` (capture the docs admit to), `CAPTURE_CAPABILITY` (capture API, no persistence or send). |
|
|
141
|
+
| Hygiene | `HYGIENE_SHELL_TRUE`, `HYGIENE_DYNAMIC_EXEC` (eval / exec / os.system), `HYGIENE_DOWNLOAD_EXEC` (`curl … \| sh`, or download + exec), `HYGIENE_OBFUSCATION` (base64 / hex blobs, `\x` escape runs), `CONCEALED_UNICODE` (invisible characters, cited by name), `CONCEALED_BLANK_RUN` (50+ blank lines with content after), `HIDDEN_COMMENT` (120+ char HTML comments), `WRITES_OUTSIDE_PACK`. |
|
|
142
|
+
|
|
143
|
+
The full rule table — severities, the exact evidence each check
|
|
144
|
+
rests on, the disclosure model, and the judgement calls — is in
|
|
145
|
+
[SKILL.md](SKILL.md).
|
|
146
|
+
|
|
147
|
+
### A hostile pack — one file per danger test
|
|
148
|
+
|
|
149
|
+
`examples/hostile-skill/` is a constructed pack whose three helper
|
|
150
|
+
scripts each trip one danger test: one reads an SSH key and an AWS
|
|
151
|
+
secret and posts them out, one screenshots the desktop in a loop and
|
|
152
|
+
posts the shots, one reads a documents file, base64-encodes it, and
|
|
153
|
+
posts it to an endpoint the docs never mention. Every endpoint is an
|
|
154
|
+
`.invalid` name — fictional by design. Verbatim output:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
$ skill-vet vet examples/hostile-skill
|
|
158
|
+
skill-vet v1.0.0 — vet · pack hostile-skill · 4 files · 1.6 KiB total
|
|
159
|
+
Frontmatter name: hostile-skill
|
|
160
|
+
Read-only: it edits nothing, writes nothing, and never executes anything in the pack — every file is analysed as static text.
|
|
161
|
+
Verdict rule: BLOCKED = at least one danger finding (a proven stealing / spying / hidden-sending combination); REVIEW = no danger finding, but at least one ERROR or WARN; CLEAN = no ERROR or WARN findings (INFO may remain). Exit 1 only for BLOCKED (or for REVIEW with --strict); exit 2 is an input error.
|
|
162
|
+
Limits: Static pattern analysis only: it reads evidence, it cannot prove a pack safe. A CLEAN verdict means no pattern fired — plain-sight social engineering, a payload assembled at runtime, and bundled binaries can all pass a static vet.
|
|
163
|
+
|
|
164
|
+
INVENTORY (4 files):
|
|
165
|
+
SKILL.md — markdown · 428 B
|
|
166
|
+
scripts/collect.py — script · 448 B
|
|
167
|
+
scripts/report.py — script · 350 B
|
|
168
|
+
scripts/snoop.py — script · 398 B
|
|
169
|
+
|
|
170
|
+
DANGER — proven stealing / spying / hidden-sending combinations (3):
|
|
171
|
+
[DANGER_STEALING] scripts/collect.py · line 12
|
|
172
|
+
STEALING combination: this file reads secrets (an SSH key or .ssh store path, line 12) and has an egress path (an HTTP client call, line 18). Credential material plus a way out is the stealing test — the pack can take what it reads off the machine.
|
|
173
|
+
fix: do not install; if you maintain this pack, remove the credential read or the egress — a legitimate pack needs at most one of them
|
|
174
|
+
[DANGER_HIDDEN_SENDING] scripts/report.py · line 15
|
|
175
|
+
HIDDEN-SENDING combination: an encoded payload reaches the network call (encoder at line 14, send at line 15) to an endpoint the docs never disclose — neither what is sent nor where it goes can be read off the pack. Concealment of what is sent, or to where, is the hidden-sending test.
|
|
176
|
+
fix: do not install until the send is disclosed in the docs and the payload is readable in the code
|
|
177
|
+
[DANGER_SPYING] scripts/snoop.py · line 12
|
|
178
|
+
SPYING combination: this file captures screen (a screenshot call, line 12), persists or sends it (an HTTP client call, line 15), and the pack's docs nowhere disclose screen capture — capture plus a way to keep or move it, in secret, is the spying test.
|
|
179
|
+
fix: do not install; undisclosed capture is never a feature
|
|
180
|
+
|
|
181
|
+
Summary: 3 findings · 3 errors · 0 warnings · 0 info · 3 danger
|
|
182
|
+
Verdict: BLOCKED — 3 proven danger combination(s) (stealing / spying / hidden sending). Do not install.
|
|
183
|
+
(exit code 1)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Note what is *not* there: no structure findings (the frontmatter is
|
|
187
|
+
valid and every referenced helper exists), and the collector's send
|
|
188
|
+
is judged once — as the egress half of stealing — not counted a
|
|
189
|
+
second time as hidden sending.
|
|
190
|
+
|
|
191
|
+
### A sloppy pack — careless, not malicious
|
|
192
|
+
|
|
193
|
+
`examples/sloppy-skill/` is the opposite case: a pack that is merely
|
|
194
|
+
badly put together. A broken reference, a name that doesn't match
|
|
195
|
+
its folder, an invisible character in the SKILL.md, `shell=True`, an
|
|
196
|
+
opaque base64 blob — and one perfectly honest network call,
|
|
197
|
+
disclosed in its docs, which earns no finding at all:
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
$ skill-vet vet examples/sloppy-skill
|
|
201
|
+
skill-vet v1.0.0 — vet · pack sloppy-skill · 2 files · 1022 B total
|
|
202
|
+
Frontmatter name: sloppy-helper
|
|
203
|
+
Read-only: it edits nothing, writes nothing, and never executes anything in the pack — every file is analysed as static text.
|
|
204
|
+
Verdict rule: BLOCKED = at least one danger finding (a proven stealing / spying / hidden-sending combination); REVIEW = no danger finding, but at least one ERROR or WARN; CLEAN = no ERROR or WARN findings (INFO may remain). Exit 1 only for BLOCKED (or for REVIEW with --strict); exit 2 is an input error.
|
|
205
|
+
Limits: Static pattern analysis only: it reads evidence, it cannot prove a pack safe. A CLEAN verdict means no pattern fired — plain-sight social engineering, a payload assembled at runtime, and bundled binaries can all pass a static vet.
|
|
206
|
+
|
|
207
|
+
INVENTORY (2 files):
|
|
208
|
+
SKILL.md — markdown · 450 B
|
|
209
|
+
scripts/tidy.py — script · 572 B
|
|
210
|
+
|
|
211
|
+
ERRORS — structure and references that do not work as shipped (1):
|
|
212
|
+
[BROKEN_REFERENCE] SKILL.md · line 15
|
|
213
|
+
referenced local file 'references/checklist.md' does not exist in the pack — the pack points at something that is not there
|
|
214
|
+
fix: add the file, or fix the reference
|
|
215
|
+
|
|
216
|
+
WARNINGS — short of danger, worth a human look (4):
|
|
217
|
+
[NAME_DIR_MISMATCH] SKILL.md
|
|
218
|
+
frontmatter name 'sloppy-helper' does not match the pack folder name 'sloppy-skill' — loaders and humans will call this pack two different things
|
|
219
|
+
fix: make the name and the folder agree
|
|
220
|
+
[CONCEALED_UNICODE] SKILL.md · line 16
|
|
221
|
+
1 invisible character(s) in this file (first at line 16): ZERO WIDTH SPACE — invisible text can carry instructions a reader never sees
|
|
222
|
+
fix: strip invisible characters from pack files
|
|
223
|
+
[HYGIENE_OBFUSCATION] scripts/tidy.py · line 11
|
|
224
|
+
a base64 blob of 120+ characters at line 11 — content encoded as one opaque blob cannot be reviewed as written
|
|
225
|
+
fix: keep pack content readable; encoded blobs belong in the open or not at all
|
|
226
|
+
[HYGIENE_SHELL_TRUE] scripts/tidy.py · line 20
|
|
227
|
+
subprocess runs with shell=True — command strings become shell input, so any value that reaches the command is an injection path
|
|
228
|
+
fix: use an argument list with shell=False
|
|
229
|
+
|
|
230
|
+
Summary: 5 findings · 1 errors · 4 warnings · 0 info · 0 danger
|
|
231
|
+
Verdict: REVIEW — no danger combination found, but 1 error(s) and 4 warning(s) need a human look before installing.
|
|
232
|
+
(exit code 0 — REVIEW; exit 1 with --strict)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### A clean pack
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
$ skill-vet vet examples/tidy-notes
|
|
239
|
+
skill-vet v1.0.0 — vet · pack tidy-notes · 3 files · 2.5 KiB total
|
|
240
|
+
Frontmatter name: tidy-notes
|
|
241
|
+
Read-only: it edits nothing, writes nothing, and never executes anything in the pack — every file is analysed as static text.
|
|
242
|
+
Verdict rule: BLOCKED = at least one danger finding (a proven stealing / spying / hidden-sending combination); REVIEW = no danger finding, but at least one ERROR or WARN; CLEAN = no ERROR or WARN findings (INFO may remain). Exit 1 only for BLOCKED (or for REVIEW with --strict); exit 2 is an input error.
|
|
243
|
+
Limits: Static pattern analysis only: it reads evidence, it cannot prove a pack safe. A CLEAN verdict means no pattern fired — plain-sight social engineering, a payload assembled at runtime, and bundled binaries can all pass a static vet.
|
|
244
|
+
|
|
245
|
+
INVENTORY (3 files):
|
|
246
|
+
SKILL.md — markdown · 790 B
|
|
247
|
+
references/style-guide.md — markdown · 392 B
|
|
248
|
+
scripts/summarize.py — script · 1.3 KiB
|
|
249
|
+
|
|
250
|
+
No findings — no structure errors, no danger combination, no hygiene warning fired. (Absence of findings is not proof of safety.)
|
|
251
|
+
Summary: 0 findings · 0 errors · 0 warnings · 0 info · 0 danger
|
|
252
|
+
Verdict: CLEAN — no errors, no warnings, no danger combinations found by the static rules.
|
|
253
|
+
(exit code 0)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### For agents
|
|
257
|
+
|
|
258
|
+
`--json` emits one object: the pack record, the full file inventory
|
|
259
|
+
(`path`, `bytes`, `kind`, `binary`, `scanned`, `symlink_out`),
|
|
260
|
+
findings (`rule`, `severity`, `danger`, `file`, `line`, `message`,
|
|
261
|
+
`fix`), summary counts that recount exactly against the findings,
|
|
262
|
+
the verdict, the verdict rule, and the limits statement. Input
|
|
263
|
+
errors — including argument errors — are a single JSON object with
|
|
264
|
+
an `error` key and exit 2. [SKILL.md](SKILL.md) states the full
|
|
265
|
+
combination table, the disclosure model, the frontmatter subset,
|
|
266
|
+
and what the tool deliberately does not claim — and makes skill-vet
|
|
267
|
+
itself installable as a skill: point your agent at this repo's
|
|
268
|
+
SKILL.md and it will vet packs before installing them.
|
|
269
|
+
|
|
270
|
+
### Tests
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
python3 -m unittest discover -s tests
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
44 tests: the three fixtures pinned to hand-counted tables; every
|
|
277
|
+
danger test in both directions (the combination fires BLOCKED; each
|
|
278
|
+
ingredient alone — secret read, undisclosed call, documented call,
|
|
279
|
+
capture alone, disclosed capture, encoded payload to a disclosed
|
|
280
|
+
endpoint — earns at most a warning); structure rules both
|
|
281
|
+
directions; verdict and exit-code boundaries including `--strict`;
|
|
282
|
+
JSON recount; and the safety proofs — nothing in a pack is ever
|
|
283
|
+
executed (a booby-trapped fixture's marker never appears), fixture
|
|
284
|
+
trees are byte-identical after runs, and the source's imports are
|
|
285
|
+
pinned to a stdlib set with no network or subprocess module.
|
|
286
|
+
|
|
287
|
+
### Honest limits
|
|
288
|
+
|
|
289
|
+
- **Static patterns are evidence, not proof.** Vet reads what a
|
|
290
|
+
pack's text shows. A pack that assembles its behaviour at runtime
|
|
291
|
+
from innocuous pieces, splits a danger combination across two
|
|
292
|
+
files (combinations are judged per file), or writes its social
|
|
293
|
+
engineering in plain, honest sentences can pass. A CLEAN verdict
|
|
294
|
+
means no pattern fired — it cannot prove a pack safe, and every
|
|
295
|
+
report says so.
|
|
296
|
+
- **Binaries are out of reach.** A bundled binary is flagged
|
|
297
|
+
precisely because vet can say nothing about what it does when run.
|
|
298
|
+
- **Disclosure is judged on two documents.** What counts as "the
|
|
299
|
+
docs" is the pack root's SKILL.md and README.md — the two files an
|
|
300
|
+
installer is expected to have read. An endpoint disclosed only in
|
|
301
|
+
a third file counts as undisclosed.
|
|
302
|
+
- **The frontmatter parser is a subset.** Scalars, inline and block
|
|
303
|
+
lists, folded continuations. A line outside the subset is reported
|
|
304
|
+
as a parse error, never guessed at — a pack using exotic YAML will
|
|
305
|
+
need that line read by a human.
|
|
306
|
+
- **Pattern tables are a snapshot.** New capture libraries,
|
|
307
|
+
credential stores, and client APIs appear constantly; the tables
|
|
308
|
+
are dated by the release, not treated as complete.
|
|
309
|
+
- **Some SKILL.md formats have no frontmatter.** Packs shipped in
|
|
310
|
+
formats that register a skill without a `---` block will be
|
|
311
|
+
reported FRONTMATTER_MISSING — which is the finding working as
|
|
312
|
+
designed: vet judges the frontmatter format, and says so when it
|
|
313
|
+
is absent.
|
|
314
|
+
|
|
315
|
+
## Contributing
|
|
316
|
+
|
|
317
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). The combination discipline
|
|
318
|
+
is the product: a lone pattern never becomes a BLOCKED verdict, and
|
|
319
|
+
contributions are held to that. Found a pack skill-vet misjudges —
|
|
320
|
+
a combination it misses or a warning it shouldn't fire? Open an
|
|
321
|
+
issue with the pack (or a minimal fixture); that is exactly the
|
|
322
|
+
feedback that improves the pattern tables.
|
|
323
|
+
|
|
324
|
+
## Security
|
|
325
|
+
|
|
326
|
+
skill-vet is itself a security tool, so its own posture is simple:
|
|
327
|
+
it has no network code, no subprocess code, no dependencies, and it
|
|
328
|
+
never executes what it scans. See [SECURITY.md](SECURITY.md) for how
|
|
329
|
+
to report a problem.
|
|
330
|
+
|
|
331
|
+
## License
|
|
332
|
+
|
|
333
|
+
MIT — see [LICENSE](LICENSE).
|
|
334
|
+
|
|
335
|
+
## Related
|
|
336
|
+
|
|
337
|
+
- [permission-audit](https://github.com/jasveerai88/permission-audit)
|
|
338
|
+
— the other half of pre-flight for agent setups: audits a
|
|
339
|
+
Claude Code permission allowlist for wildcard grants and
|
|
340
|
+
dangerous modes before they hurt you.
|
|
341
|
+
|
|
342
|
+
## Support
|
|
343
|
+
|
|
344
|
+
If skill-vet stops a bad install, consider
|
|
345
|
+
[sponsoring](https://github.com/sponsors/jasveerai88).
|