-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathskillspector-allow.yml
More file actions
235 lines (234 loc) · 11.8 KB
/
Copy pathskillspector-allow.yml
File metadata and controls
235 lines (234 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# SkillSpector false-positive allowlist.
#
# SkillSpector's static scan is high-recall / moderate-precision and has no
# native per-finding suppression. This file is the auditable place to record
# findings that are genuinely false positives so the CI gate
# (.github/scripts/skillspector_gate.py) does not fail on them. Everything not listed
# here still fails the build at HIGH/CRITICAL.
#
# Each entry suppresses ONE rule for ONE file within ONE skill:
# skill: skill directory name under skills/
# rule: SkillSpector rule id (e.g. YR1)
# file: path as it appears in the report, relative to the skill dir
# match: (optional) substring that must appear in the finding message, so
# the suppression stays scoped to the specific signature
# reason: why this is a false positive (keep it accurate and specific)
#
# Add entries sparingly and only when the finding is demonstrably benign.
suppressions:
- skill: rocm-doctor
rule: YR1
file: scripts/apply_fix.py
match: backdoor_persistence
reason: >-
False positive. The 'backdoor_persistence' YARA rule's $bashrc_persist
string matches any `echo ... >> ~/.bashrc`. Here it is the documented
remediation that appends `export PATH="/opt/rocm/bin:$PATH"` so ROCm
binaries land on PATH after install. Standard ROCm setup guidance, not a
persistence backdoor or payload.
- skill: rocm-doctor
rule: YR1
file: scripts/diagnose.py
match: backdoor_persistence
reason: >-
False positive. Same $bashrc_persist match: diagnose.py prints the
remediation command `echo 'export PATH=<bin>:$PATH' >> ~/.bashrc` (or
~/.zshrc) for the user to add ROCm/HIP to PATH. No payload, no SSH key
injection, no hidden user.
- skill: rocm-doctor
rule: OH1
file: scripts/apply_fix.py
match: Unvalidated Output Injection
reason: >-
False positive. The flag is on the generic `_run(cmd: list[str], ...)`
helper, which calls `subprocess.run(cmd, ..., shell defaults to False)`
with a list-form argv, so there is no shell interpolation. Every `cmd`
is a hardcoded argv list assembled in-script (e.g.
`["usermod","-a","-G","render,video",user]`, `["modprobe","amdgpu"]`);
the only dynamic pieces are the local username from `$USER`/`$LOGNAME`
and binary paths resolved via `shutil.which`. No LLM/model output ever
reaches this sink, so there is nothing to validate or sanitize.
- skill: rocm-doctor
rule: OH1
file: scripts/examine.py
match: Unvalidated Output Injection
reason: >-
False positive. Same generic `_run(cmd: list[str], ...)` helper as in
apply_fix.py: list-form `subprocess.run` with no shell=True. The read-only
probes only ever pass fixed argv lists (`["rocminfo"]`,
`["lspci","-nn","-D"]`, the PowerShell/CIM `Get-CimInstance` probes, the
framework binary from `shutil.which`). No model output flows into the
command, and there is no shell to inject into.
- skill: rocm-doctor
rule: PE3
file: scripts/examine.py
match: Credential Access
reason: >-
False positive. Line 493 is a code comment ("Resolve uid/gid to names via
/etc/passwd & /etc/group") describing how `_stat_device` maps a device's
owner uid/gid to names. The actual resolution uses the stdlib `pwd`/`grp`
modules (`pwd.getpwuid` / `grp.getgrgid`), not any read of /etc/passwd,
/etc/shadow, .env, or token files. No credential material is accessed.
- skill: local-ai-use
rule: SC2
file: SKILL.md
match: External Script Fetching
reason: >-
False positive. The flagged `curl ... | python -c ...` is not fetching or
executing a remote script: `curl` POSTs an image-generation request to the
local loopback Lemonade Server, and the piped `python -c` only
base64-decodes the JSON response body and writes it to `out.png`. No
remote code is downloaded or run.
- skill: local-ai-use
rule: SC2
file: templates/local-ai-rule.md
match: External Script Fetching
reason: >-
False positive. Same pattern as SKILL.md: the `curl ... | python -c ...`
in the installable rule template POSTs to the local Lemonade Server and
pipes the JSON response into `python -c` purely to base64-decode the image
bytes into `out.png`. No remote script is fetched or executed.
- skill: local-ai-use
rule: OH1
file: scripts/setup_local_ai.py
match: Unvalidated Output Injection
reason: >-
False positive. Both flagged calls (lines 98 and 128) use list-form
subprocess.run argv with no shell=True, so there is no shell
interpolation. Line 98 is fully hardcoded (`lemonade list --downloaded
--json`); line 128 is `lemonade pull <model>` where `model` comes from
argparse defaults / explicit --image-model/--tts-model/--stt-model flags,
not from LLM or model output. Nothing here consumes unvalidated model
output, so there is no injection sink to sanitize.
- skill: local-ai-use
rule: TM2
file: SKILL.md
match: Chaining Abuse
reason: >-
False positive. Line 103 is the documented Ubuntu/Debian install
one-liner `sudo add-apt-repository -y ppa:lemonade-team/stable &&
sudo apt-get update && sudo apt-get install -y lemonade-server
lemonade-desktop`. The `&&` chaining is the standard apt install
sequence (add PPA, refresh index, install package), not tool/command
chaining of untrusted or model-derived steps. No LLM output feeds the
chain and each command is a fixed, reviewable install step.
- skill: local-ai-use
rule: P2
file: templates/local-ai-rule.md
match: Hidden Instructions
reason: >-
False positive. Line 1 is the `<!-- BEGIN amd-skills:local-ai-use -->`
HTML comment, a benign machine-readable marker that setup_local_ai.py uses
to locate and replace the rule block in AGENTS.md in place on re-runs. It
carries no instructions; the surrounding rule text is plain, reviewable
content by design (it is the installable routing rule itself).
- skill: serving-llms-on-instinct
rule: SC2
file: data/recipes_cache.json
match: External Script Fetching
reason: >-
False positive. The flag is on a `"guide"` markdown string (a recipe doc
embedded in this JSON cache, not runnable code). Its shell snippets are
illustrative: `uv pip install ... --extra-index-url https://wheels.vllm.ai/nightly`
installs vLLM from an HTTPS package index (the recommended-safe pattern),
and `curl http://localhost:8000/... | python3 -m json.tool` pipes a
localhost API response into a JSON pretty-printer. There is no
download-and-execute of a remote script (no `curl ... | bash`/`sh`).
- skill: serving-llms-on-instinct
rule: P6
file: data/recipes_cache.json
match: Direct Prompt Extraction
reason: >-
False positive. The flag is on a `"guide"` markdown string (the
Ministral-3-Instruct recipe doc, not runnable code). The matched Python
example downloads the model's own publicly published `SYSTEM_PROMPT.txt`
via `hf_hub_download` and passes it as the `system` role of a chat request
(Mistral's documented setup) — it constructs a prompt, it does not reveal
or extract any hidden system prompt. The only output printed is the
model's answer (`response.choices[0].message.content`). The trigger is
merely the literal token `SYSTEM_PROMPT` in benign example code.
- skill: serving-llms-on-instinct
rule: TM2
file: reference.md
match: Chaining Abuse
reason: >-
False positive. Line 92 is a Troubleshooting one-liner that disables
kernel NUMA balancing for GPU workloads:
`echo 0 | sudo tee /proc/sys/kernel/numa_balancing`. The `|` is just the
idiomatic way to write a root-owned /proc file (echo piped into `sudo
tee`), not multi-step tool/command chaining of untrusted or model-derived
steps. It is a single fixed, reviewable, human-run sysctl write — no LLM
output feeds the pipe and there is no chain depth to bound.
- skill: serving-llms-on-instinct
rule: TM1
file: scripts/detect.py
match: Tool Parameter Abuse
reason: >-
False positive. Line 32 uses `subprocess.run(cmd, shell=True, ...)`, but
`shell=True` is intentional and safe here: every `cmd` passed to `_run`
is a fixed in-script literal (`amd-smi static --asic --vram --json`,
`amd-smi version --json`, and their `sudo` retries) that relies on no
shell metacharacters from user input. The only user-controlled values
(`--host`/`--user`/`--port`) never enter the shell string — they flow
solely into the SSH branch as list-form argv (`ssh ... ssh_target cmd`,
no shell), and `port` is int-coerced by argparse. No untrusted or model
output reaches the shell, so there is no parameter abuse to reject.
- skill: serving-llms-on-instinct
rule: TM1
file: scripts/validate.py
match: Tool Parameter Abuse
reason: >-
False positive. Same `_run` helper as detect.py: line 33 uses
`subprocess.run(cmd, shell=True, ...)` where every `cmd` is a hardcoded
diagnostic literal (`test -e /dev/kfd ...`, `ls /dev/dri/renderD* ...`,
`cat /proc/sys/kernel/numa_balancing ...`, `printenv HF_TOKEN ...`, etc.)
that deliberately uses shell pipes/redirects/globs. The dynamic inputs
(`--host`/`--user`/`--port`) only reach the SSH branch as list-form argv,
never the shell string, and `port` is int-coerced. No untrusted/model
output is interpolated into the command.
- skill: serving-llms-on-instinct
rule: TM2
file: scripts/validate.py
match: Chaining Abuse
reason: >-
False positive. The flagged lines are the NUMA-balancing fix
`echo 0 | sudo tee /proc/sys/kernel/numa_balancing`. Line 122 only runs
it under the explicit opt-in `--auto-fix` flag (user-approved), while
lines 130 and 137 are human-readable `"fix"` advisory strings that are
never executed. The `|` is the idiomatic root-owned /proc write (echo
into `sudo tee`), a single fixed sysctl command — not multi-step tool
chaining of untrusted or model-derived steps.
- skill: serving-llms-on-instinct
rule: E2
file: scripts/estimate_vram.py
match: Env Variable Harvesting
reason: >-
False positive. Line 175 reads `HF_TOKEN` via `os.environ.get`, which is
strictly required: it is passed only to `_fetch`, which sets it as the
`Authorization: Bearer` header on requests to `https://huggingface.co`
(the token's intended recipient) so the tool can read safetensors/config
metadata for gated or private models. The token is never logged, printed,
or transmitted anywhere else — the emitted JSON contains only model and
VRAM fields.
- skill: serving-llms-on-instinct
rule: E2
file: scripts/validate.py
match: Env Variable Harvesting
reason: >-
False positive. Line 151 runs `printenv HF_TOKEN | head -c 4` purely as a
presence check; the captured 4-char value is never emitted — only
`out.strip()` truthiness is tested to decide whether to advise the user
that HF_TOKEN is unset (needed for gated models). No credential is logged
or transmitted.
- skill: serving-llms-on-instinct
rule: P5
file: data/recipes_cache.json
match: Harmful Content Injection
reason: >-
False positive. Line 3524 is the `"guide"` for Qwen3Guard-Gen, a
text-only safety/guardrail classifier model. The matched string
("Tell me how to make a bomb.") is the demo *input* used to show the
moderation model correctly classifying the request as unsafe — the
documented output is `# Safety: Unsafe` / `# Categories: Violent`. No
harmful instructions are present; it is content-moderation documentation,
the opposite of harmful-content injection.