@tetherto/mdk-skill 0.0.0 → 0.12.1

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 (62) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +133 -0
  3. package/dist/skills/mdk/SKILL.md +114 -0
  4. package/dist/skills/mdk/references/architecture.md +89 -0
  5. package/dist/skills/mdk/references/glossary.md +27 -0
  6. package/dist/skills/mdk/references/mdk-contract.schema.json +138 -0
  7. package/dist/skills/mdk/references/package-index.md +53 -0
  8. package/dist/skills/mdk/references/protocol.md +95 -0
  9. package/dist/skills/mdk-create-app/SKILL.md +231 -0
  10. package/dist/skills/mdk-deployment/SKILL.md +161 -0
  11. package/dist/skills/mdk-gateway-plugin/SKILL.md +192 -0
  12. package/dist/skills/mdk-gateway-plugin/references/controller-patterns.md +99 -0
  13. package/dist/skills/mdk-gateway-plugin/references/plugin-authoring.md +121 -0
  14. package/dist/skills/mdk-publish-security/SKILL.md +177 -0
  15. package/dist/skills/mdk-publish-security/references/vuln-classes.md +151 -0
  16. package/dist/skills/mdk-publish-security/scripts/scan-packages.mjs +544 -0
  17. package/dist/skills/mdk-site-sizing/SKILL.md +160 -0
  18. package/dist/skills/mdk-site-sizing/eval/held-out.json +104 -0
  19. package/dist/skills/mdk-site-sizing/eval/profiles/cap-100devices-2workers-mixed.json +24 -0
  20. package/dist/skills/mdk-site-sizing/eval/profiles/cap-100devices-2workers.json +23 -0
  21. package/dist/skills/mdk-site-sizing/eval/profiles/cap-10devices-1workers.json +23 -0
  22. package/dist/skills/mdk-site-sizing/eval/profiles/cap-15devices-2workers.json +24 -0
  23. package/dist/skills/mdk-site-sizing/eval/profiles/cap-200devices-4workers.json +23 -0
  24. package/dist/skills/mdk-site-sizing/eval/profiles/cap-500devices-4workers.json +23 -0
  25. package/dist/skills/mdk-site-sizing/eval/profiles/cap-50devices-2workers.json +23 -0
  26. package/dist/skills/mdk-site-sizing/references/envelope.json +284 -0
  27. package/dist/skills/mdk-site-sizing/references/envelope.md +42 -0
  28. package/dist/skills/mdk-site-sizing/scripts/compile-envelope.mjs +45 -0
  29. package/dist/skills/mdk-site-sizing/scripts/eval-held-out.mjs +50 -0
  30. package/dist/skills/mdk-site-sizing/scripts/lib.mjs +591 -0
  31. package/dist/skills/mdk-site-sizing/scripts/parse-site.mjs +25 -0
  32. package/dist/skills/mdk-site-sizing/scripts/size-site.mjs +49 -0
  33. package/dist/skills/mdk-ui-component/SKILL.md +207 -0
  34. package/dist/skills/mdk-ui-component/references/page-recipe.md +78 -0
  35. package/dist/skills/mdk-ui-component/references/ui-registry.json +1 -0
  36. package/dist/skills/mdk-worker-plugin/SKILL.md +198 -0
  37. package/dist/skills/mdk-worker-plugin/assets/mdk-contract.template.json +45 -0
  38. package/dist/skills/mdk-worker-plugin/assets/worker-template/README.md +93 -0
  39. package/dist/skills/mdk-worker-plugin/assets/worker-template/mdk-contract.json +26 -0
  40. package/dist/skills/mdk-worker-plugin/assets/worker-template/mock/server.js +93 -0
  41. package/dist/skills/mdk-worker-plugin/assets/worker-template/package.json +23 -0
  42. package/dist/skills/mdk-worker-plugin/assets/worker-template/smoke.config.js +41 -0
  43. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/client.js +47 -0
  44. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/commands/reboot.js +5 -0
  45. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/commands/set-power-mode.js +10 -0
  46. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/hashrate-rt.js +5 -0
  47. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/power-mode.js +5 -0
  48. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/power.js +5 -0
  49. package/dist/skills/mdk-worker-plugin/assets/worker-template/src/telemetry/temperature.js +5 -0
  50. package/dist/skills/mdk-worker-plugin/references/contract-authoring.md +135 -0
  51. package/dist/skills/mdk-worker-plugin/references/device-families.md +96 -0
  52. package/dist/skills/mdk-worker-plugin/references/local-testing.md +134 -0
  53. package/dist/skills/mdk-worker-plugin/references/mdk-contract.schema.json +138 -0
  54. package/dist/skills/mdk-worker-plugin/references/worker-base-api.md +152 -0
  55. package/dist/skills/mdk-worker-plugin/scripts/validate-contract.mjs +129 -0
  56. package/dist/skills/mdk-worker-plugin/scripts/worker-smoke.mjs +256 -0
  57. package/package.json +47 -1
  58. package/src/assemble.mjs +11 -0
  59. package/src/index.d.ts +57 -0
  60. package/src/index.mjs +254 -0
  61. package/src/install.mjs +57 -0
  62. package/src/sources.map.json +34 -0
@@ -0,0 +1,177 @@
1
+ ---
2
+ name: mdk-publish-security
3
+ description: >
4
+ Run the pre-publish security audit for every publishable @tetherto/mdk-*
5
+ package (or any non-private package in an npm monorepo). Use when preparing an
6
+ npm release, when asked to "security check the packages", "audit before
7
+ publish", "run the publish checklist", or to review packages for auth bypass,
8
+ injection, command execution, path traversal, SSRF, prototype pollution,
9
+ unsafe deserialization, secret exposure, crypto mistakes, insecure defaults,
10
+ RPC trust boundaries, privilege escalation or TOCTOU issues, or to check
11
+ that packed tarballs install and import cleanly, what consumers get from
12
+ npm audit without the root overrides, and who owns the npm scope.
13
+ metadata:
14
+ suite: mdk-developer-skill
15
+ mdk_version: "0.10.0"
16
+ license: Apache-2.0
17
+ ---
18
+
19
+ # Pre-publish security audit
20
+
21
+ Produces one Markdown report listing every publishable package, every check run
22
+ on it, and the issues that must be fixed before `npm publish`. The checks combine
23
+ the repo's `PUBLISH_CHECKLIST.md` (security section + per-package extras) and the
24
+ publish blockers in `NPM_PACKAGES.md` with a manual review for 18 vulnerability
25
+ classes ([`references/vuln-classes.md`](./references/vuln-classes.md)).
26
+
27
+ This skill never edits package source, never publishes, and never runs install
28
+ scripts of dependencies. Without `--smoke` it only reads the checkout and writes
29
+ the report. **`--smoke` is not read-only:** `npm pack` runs each package's *own*
30
+ `prepack`/`prepare` script (for example it rebuilds `packages/mdk-skill/dist/`),
31
+ and the smoke step then installs the tarballs into a temp directory outside the
32
+ repo and imports every package entry point and runs every `bin`. That executes
33
+ the packages' code, so only run `--smoke` on a checkout you trust.
34
+
35
+ ## 1. Inventory
36
+
37
+ From the repo root:
38
+
39
+ ```bash
40
+ git ls-files '*package.json' | grep -Ev '(^|/)(node_modules|dist|templates|fixtures?)/' \
41
+ | xargs grep -L '"private": true'
42
+ ```
43
+
44
+ The filter drops scaffolding templates and generated output, which are not
45
+ packages. The scan script applies the same filter.
46
+
47
+ Cross-check against the table in `NPM_PACKAGES.md` (if present). A package that
48
+ is publishable but missing from the doc, or vice versa, is itself a finding.
49
+
50
+ ## 2. Mechanical scan (all packages, one command)
51
+
52
+ ```bash
53
+ SCAN_DIR="$(mktemp -d)" # private dir; never a fixed /tmp path
54
+ node <this-skill>/scripts/scan-packages.mjs --audit --smoke --registry --out "$SCAN_DIR/mdk-scan.md"
55
+ node <this-skill>/scripts/scan-packages.mjs --audit --smoke --registry --json --out "$SCAN_DIR/mdk-scan.json"
56
+ # one package: --pkg backend/core/gateway (repeatable)
57
+ # keep the smoke project for `npm ls <dep>`: --keep-smoke
58
+ ```
59
+
60
+ `--out` refuses to overwrite an existing file or follow a symlink. `--audit`,
61
+ `--smoke` and `--registry` need network; without them the scan is offline. It runs `npm pack --dry-run --ignore-scripts` per package and checks,
62
+ on exactly the files that would ship. "Blocker" refers to the section of that
63
+ name in `NPM_PACKAGES.md`:
64
+
65
+ | Check | Source | What fails |
66
+ | --- | --- | --- |
67
+ | `files-allowlist` | Blocker "no `files` allowlist" / checklist "Tarball contents" | No `files` field |
68
+ | `tarball-contents` | Checklist "Tarball contents" | tests, mocks, fixtures, db/, `.env`, keys, real `config/*.json`, `.sh` in the tarball |
69
+ | `escaping-import` | Blocker "relative `require()`s" | Literal `require('../..')` that resolves outside the package dir |
70
+ | `undeclared-dep` | Blocker "missing dependency declarations" / "Tarball smoke test" | Bare import not in `dependencies` (dev-only counts as missing) |
71
+ | `dep-source` | Checklist "Versions and lockfile" | `file:`/`workspace:`/`link:`/git deps in a published manifest |
72
+ | `loose-range` | Checklist "Version ranges" | `*`, `latest`, `x` or unbounded `>=` in `dependencies` (high for the package's own scope) |
73
+ | `private-dep` | Checklist "Version ranges" | Depends on a package that is `"private": true` in this repo |
74
+ | `dev-peer` | Checklist "Version ranges" / UI class U10 | A dev tool (`vitest`, `jest`, `@testing-library/*`, `vite`, `typescript`, …) is a required `peerDependency`, so npm 7+ installs it for every consumer |
75
+ | `root-override` / `package-overrides` | Checklist "Consumer-view audit" | A dep the root `overrides` patches, or `overrides` in the package itself — neither reaches consumers |
76
+ | `publish-access` | Blocker "scoped packages publish as restricted" | Scoped package without `publishConfig.access` |
77
+ | `repository` | Blocker "missing `repository` metadata" / provenance | No `repository` |
78
+ | `prepack-build` | Blocker "no pre-publish build" | `main`/`bin` points at missing build output with no `prepack` |
79
+ | `entry-missing` | Checklist "Tarball smoke test" | A `main`, `exports` or `bin` target is not in the tarball |
80
+ | `bin-shebang` | Checklist "Tarball smoke test" | A `bin` file without a `#!` line |
81
+ | `exports-map` | Hygiene (low) | No `exports` map, so every shipped file is importable |
82
+ | `install-scripts` | Checklist "Install scripts" | `preinstall`/`install`/`postinstall` |
83
+ | `secrets` | Checklist "Secrets" | Key/token patterns, hard-coded credentials, private IPs, internal hosts |
84
+ | `npm-audit` | Checklist "Dependency audit" (`--audit`) | Moderate+ advisories in prod deps of that workspace |
85
+ | `smoke-pack` / `smoke-install` / `smoke-import` / `smoke-bin` | Checklist "Tarball smoke test" (`--smoke`) | Packs every package, installs all tarballs together in a temp project outside the repo, imports each `main`/`exports` entry and runs each `bin --help`. Catches runtime-built paths the static `escaping-import` check misses. A load-time throw that is not a missing module is reported low — confirm it is intentional |
86
+ | Consumer-view audit | Checklist "Consumer-view audit" (`--smoke`) | `npm audit --omit=dev` in the smoke project; repo-level line naming the vulnerable packages. The workspace audit can be clean while this is not |
87
+ | `registry-unclaimed` / `registry-version` / `registry-owner` | Release checks (`--registry`) | Name not on npm yet; version already published; published name points at a different repository (squat). Also reports `npm whoami` and how many packages the scope already holds |
88
+ | SAST leads | Checklist "Static analysis" | Grep hits per vulnerability class in shipped runtime code, including the UI classes (`xss` HTML sinks, `url` navigation sinks and `_blank` without `noopener`, `browser-storage`, `postmessage`) — **triage, do not report raw** |
89
+
90
+ Then run the repo-wide checks the script does not cover, and record the outcome
91
+ (including "tool not installed" — never silently skip):
92
+
93
+ ```bash
94
+ npm audit --audit-level=moderate # root, all workspaces
95
+ npm audit signatures # registry signatures of installed deps
96
+ npx --yes audit-ci@7.1.0 --config .github/scripts/audit-ci.jsonc # downloads; needs network
97
+ npx --yes license-checker@25.0.1 --production --onlyAllow 'Apache-2.0;MIT;ISC;BSD-2-Clause;BSD-3-Clause;0BSD;BlueOak-1.0.0;CC0-1.0;Python-2.0;Unlicense' --excludePrivatePackages # downloads; needs network
98
+ gitleaks detect --no-banner # if installed; also on each extracted tarball
99
+ semgrep --config p/javascript --config p/nodejs <pkg> # if installed
100
+ grep -rn 'uses:' .github/workflows | grep -v '@[0-9a-f]\{40\}' # actions not pinned to a SHA
101
+ git diff <lastTag> -- '**/package.json' # new dependencies since last release
102
+ npm view <dep> time.modified deprecated # per new dep: age (<7 days is a flag) and deprecation
103
+ npm sbom --omit dev --sbom-format cyclonedx -w <name> # attach one SBOM per package to the report
104
+ ```
105
+
106
+ `audit-ci` and `license-checker` are not repo dependencies, so `npx` downloads
107
+ and runs them. Keep the exact versions above (bump only to a release that is at
108
+ least two weeks old, checked with `npm view <pkg> time --json`), never drop the
109
+ `@version`, and record "not run (no network)" when offline.
110
+
111
+ Scope and account checks need `npm login` as a publisher. Record "not run" if
112
+ nobody with publish rights is available; never infer ownership from 404s:
113
+
114
+ ```bash
115
+ npm whoami
116
+ npm org ls <scope-without-@> # you are a member with publish rights
117
+ npm profile get # "two-factor auth" is auth-and-writes
118
+ npm access get status <name> # after first publish: public as intended
119
+ ```
120
+
121
+ If `--registry` shows the scope has no packages and cannot be listed, the scope
122
+ may be unclaimed. Anyone can then register it, and every doc that says
123
+ `npm install @scope/...` installs their code. Report it as **High** until the
124
+ org exists.
125
+
126
+ `npm` may be a shell alias/function in the user's profile; scripts call the
127
+ binary directly, so do the same (`command npm …`) when results differ.
128
+
129
+ ## 3. Manual review (per package, 18 classes + UI classes for browser packages)
130
+
131
+ Mechanical checks cannot find auth bypasses or SSRF. For each package:
132
+
133
+ 1. Read its `package.json`, README and entry point; list its boundaries using the
134
+ table in [`references/vuln-classes.md`](./references/vuln-classes.md).
135
+ 2. Enumerate every route, RPC handler, action, MCP tool and exported function
136
+ that accepts external data. Follow each to its sinks (fs, process, network,
137
+ storage, logs, responses).
138
+ 3. Walk all 18 classes, and for browser packages (`ui/packages/*`) also the UI
139
+ classes U1–U12 in the same reference. Treat device, pool and LLM strings rendered
140
+ by the UI as attacker-controlled. Use the package's SAST leads from step 2 as starting
141
+ points, and read the surrounding code before deciding.
142
+ 4. Run the package-specific extras from `PUBLISH_CHECKLIST.md` → "Extra checks
143
+ by package" (e.g. gateway: every route requires auth, body/rate limits, CORS,
144
+ plugin resolution confined to allowed roots; workers: Modbus write allowlist,
145
+ no shell interpolation of miner commands, TLS to pools; mcp: `safety` flags).
146
+ 5. For each class record pass / issue / n/a. An issue needs `file:line`, who the
147
+ attacker is, what they gain, and the fix.
148
+
149
+ With many packages, fan this out: one subagent per package (or per small group of
150
+ similar workers) with the package path, its scan section, and
151
+ `references/vuln-classes.md`. Have each return structured findings; verify every
152
+ Critical/High yourself by reading the cited lines before it goes in the report.
153
+
154
+ **Do not** report: grep leads you have not read, issues only reachable from
155
+ tests/mocks that do not ship (report the *shipping* of them instead), or style
156
+ nits. **Do** report false-negative risk: code the review could not cover (e.g. a
157
+ package whose source is not in the tarball, like a TS `dist/`).
158
+
159
+ ## 4. Report
160
+
161
+ Write `PUBLISH_SECURITY_REPORT.md` at the repo root (or where the user asks):
162
+
163
+ 1. **Header** — date, branch, commit, version, tools run and their versions, tools
164
+ unavailable.
165
+ 2. **Summary table** — one row per package: blockers / high / medium / low,
166
+ verdict (*Ready* / *Fix before publish* / *Blocked*).
167
+ 3. **Repo-wide results** — audit, signatures, audit-ci, licences, secrets,
168
+ workflow pinning, SAST availability.
169
+ Include the smoke install result, the consumer-view audit, and the registry
170
+ and scope results.
171
+ 4. **Per package** — a checklist of every step executed with its result (✅ / ❌ /
172
+ ⚠️ / n/a), then "Issues to fix before publishing" ordered by severity, each with
173
+ `file:line`, impact, and fix.
174
+ 5. **Cross-cutting fixes** — the same issue in many packages, stated once.
175
+
176
+ Keep the issue list to things that must change. Link the checklist and
177
+ `NPM_PACKAGES.md` instead of repeating them.
@@ -0,0 +1,151 @@
1
+ # Vulnerability classes and MDK trust boundaries
2
+
3
+ The manual-review half of `mdk-publish-security`. For each publishable package, walk
4
+ every class below, starting from the package's **entry points** (the boundaries
5
+ listed first), not from the grep leads. A grep lead tells you where to look; a
6
+ finding needs a concrete attacker, a reachable path and an impact.
7
+
8
+ ## Where attacker-controlled data enters MDK
9
+
10
+ | Boundary | Packages | Who can send data | Notes |
11
+ | --- | --- | --- | --- |
12
+ | Gateway HTTP (Fastify routes, plugin routes, cached routes, static files, OAuth callback) | `mdk-gateway`, `mdk-core` (`startGateway`) | Any network peer that reaches the bind address; authenticated operators | Every route needs auth + schema validation + body/rate limits |
13
+ | MCP tools (stdio / HTTP via `hono`) | `mdk-mcp` | The LLM driving the tools — and therefore anything that reaches its context (device names, logs, pool data) | Treat tool arguments as untrusted; write/command tools need explicit authorisation and must honour manifest `safety` flags |
14
+ | HRPC / `@hyperswarm/rpc` over the DHT (Kernel ↔ Worker, client ↔ Kernel) | `mdk-kernel`, `mdk-client`, `mdk-worker`, `mdk-core`, all workers | Any DHT peer that knows/derives the public key, unless the whitelist rejects it | Check: public-key whitelist enforced *before* the handler runs, envelope validated, unknown actions rejected, payload size bounded |
15
+ | Device / vendor responses (miner CGMiner API, Modbus/TCP registers, container HTTP APIs, pool REST APIs) | all `mdk-worker-*` (private today; review if one becomes publishable) | A compromised or spoofed device, a MITM on plain-http LAN traffic, the pool/vendor | Responses flow into telemetry, alerts, UI and MCP tool output — validate types and sizes, never `eval`/interpolate them |
16
+ | Config files and env (`config/*.json`, `mdk.yaml`, env vars) | all | Local operator (trusted) but often copied from examples | Insecure *defaults* matter here: what happens when a field is missing |
17
+ | CLI arguments and scaffold names | `mdk-cli` | The local user, or a script/agent invoking `mdk` | Names reach paths, `package.json`, shell hints |
18
+ | Skill content consumed by coding agents | `mdk-skill` | Whoever authors the skill text; the agent executes it | Instructions must not tell an agent to run destructive or network-fetching commands |
19
+ | npm consumers (the SDK surface itself) | all | Third-party apps that `require()` the package | Exported APIs must not trust caller input for paths, URLs, or shell; defaults must be safe when options are omitted |
20
+ | Browser: data rendered by UI packages (device, container, PDU and pool names, telemetry keys, alerts) | `ui/packages/*` (`mdk-react-devkit`, `mdk-react-adapter`) | Whoever can name or rename a device, a compromised or spoofed worker or device, a third-party worker plugin | Rendered in the operator's authenticated session, so an HTML sink is privilege escalation into device control |
21
+ | Browser: LLM output streamed to the UI | `mdk-ui-agent` | Anything that reaches the model's context (prompt injection through device, pool and log data) | Treat every token, tool name, tool arg and tool result as attacker-controlled |
22
+ | Browser: URL, storage and session (`?authToken=`, `localStorage`, `sessionStorage`) | `mdk-ui-foundation`, `mdk-react-adapter`, `mdk-ui-agent` | Anyone who can get an operator to open a link; any same-origin script; the next user of a shared browser | Session adoption, token persistence and refresh, cross-user leftovers |
23
+
24
+ ## The 18 classes
25
+
26
+ For each, the MDK-specific questions to answer. Record **pass**, **issue** (with
27
+ `file:line`, attacker, impact, fix) or **n/a** (with the reason) per package.
28
+
29
+ 1. **Authentication/authorization bypass** — Can a route or RPC handler be reached
30
+ with no token, an expired token, or a token for another role? Does the DHT
31
+ whitelist accept an empty list as "allow all"? Are there `skipAuth`/dev flags
32
+ that survive into production?
33
+ 2. **Missing authorization on API/RPC methods** — Enumerate every registered
34
+ route, RPC `respond()` / action handler and MCP tool. Mark which check gates it.
35
+ Commands that change device state (reboot, power mode, pool switch, Modbus
36
+ write, factory reset) need a write/admin permission, not just "authenticated".
37
+ 3. **Unsafe input handling** — Are params validated against the contract/manifest
38
+ (type, range, enum, length)? Unbounded arrays, time ranges, page sizes,
39
+ `parseInt` without radix/range, regex built from input (ReDoS).
40
+ 4. **Injection** — SQL (`better-sqlite3`/sqlite queries with template literals),
41
+ LevelDB/Hyperbee key injection via unescaped prefixes, log injection, header
42
+ injection, template/HTML injection into UI-facing strings, prompt injection into
43
+ MCP tool output.
44
+ 5. **Command execution** — `child_process`, `shell: true`, `eval`, `new Function`,
45
+ `vm`, dynamic `require()`/`import()` of a path that a config, manifest or request
46
+ can influence (plugin loaders!).
47
+ 6. **Path traversal** — Plugin `package`/directory resolution, static file serving,
48
+ store/db dirs, scaffold targets, skill install targets, any `path.join(base, x)`
49
+ without `path.resolve` + prefix check. Watch symlinks.
50
+ 7. **SSRF** — Device `address`/`port` and pool URLs supplied via RPC
51
+ (`registerThing`, config updates) or HTTP, then fetched by the worker. Can a
52
+ caller point a worker at `169.254.169.254`, localhost admin ports or an internal
53
+ host? Redirect following?
54
+ 8. **Prototype pollution** — Deep merge / `Object.assign` / `obj[key] = v` with keys
55
+ from JSON payloads, query strings, config or device responses. `__proto__`,
56
+ `constructor.prototype`.
57
+ 9. **Unsafe deserialization** — `JSON.parse` of peer data without try/catch or size
58
+ cap (crash = DoS of the kernel), `v8.deserialize`, YAML `load`, msgpack/compact
59
+ encodings from untrusted peers, reviving class instances.
60
+ 10. **Sensitive information exposure** — Stack traces, internal paths, config,
61
+ device passwords or pool credentials returned in API/RPC/MCP responses; verbose
62
+ error messages; debug endpoints.
63
+ 11. **Cryptographic mistakes** — TLS verification disabled, weak hashes/ciphers,
64
+ `Math.random` for ids/tokens/nonces, non-constant-time token compare, keys or
65
+ seeds derived from predictable input, key material written world-readable.
66
+ 12. **Insecure defaults** — Bind `0.0.0.0` by default, auth off when config omits
67
+ it, permissive CORS, debug on, default passwords (`admin`/`root`) in shipped
68
+ config/README examples, plain-http to devices/pools, unlimited body size.
69
+ 13. **Trust-boundary problems between SDK and consumers** — Does an exported
70
+ function trust its caller for something it should validate (paths, URLs,
71
+ plugin dirs)? Does the SDK mutate caller-owned objects or globals? Does it
72
+ `process.exit()`, install signal handlers, or read env vars the consumer did not
73
+ opt into? Peer/optional deps that change security posture?
74
+ 14. **Network/RPC endpoints accepting attacker-controlled data** — List each
75
+ listener (HTTP port, RPC server key, MCP transport, mock servers that might be
76
+ started in prod) and what reaches it without auth.
77
+ 15. **Privilege escalation** — Can a read-only/operator role invoke admin actions?
78
+ Can a worker (lower trust) make the kernel act on another worker's devices? Can
79
+ a plugin escalate to gateway-wide config?
80
+ 16. **Race / TOCTOU** — `existsSync` then write; check-then-act on command state
81
+ machines; concurrent state pull / timer reset; action approval flows where state
82
+ can change between approve and execute; temp files with predictable names.
83
+ 17. **Dangerous filesystem operations** — `rm -rf`/`rmSync({recursive})` on a path
84
+ derived from config or input, `chmod`, symlink following, writing into
85
+ `node_modules`, overwriting user files during scaffold/install.
86
+ 18. **Secrets exposed through logs or API responses** — Logging of tokens,
87
+ `Authorization` headers, device passwords, pool API keys, DHT seeds/secret keys,
88
+ full config objects, or request bodies containing any of them; audit logger
89
+ redaction.
90
+
91
+ ## UI classes (browser packages)
92
+
93
+ For packages that run in a browser (`ui/packages/*`), walk these **in addition to** the
94
+ 18 classes above. Most of the 18 are written for servers, so several are `n/a` for UI
95
+ code; these cover what replaces them. Record pass / issue / n/a in the same way.
96
+
97
+ - **U1. XSS.** `dangerouslySetInnerHTML`, `innerHTML`/`outerHTML`/`insertAdjacentHTML`,
98
+ HTML built as strings (chart tooltips, formatters), markdown or HTML rendering
99
+ (`rehype-raw`, custom remark/rehype plugins), SVG, `style` attributes built from data.
100
+ Trace every device, pool, alert or agent string to the sink.
101
+ - **U2. URL injection.** `href`/`src`/`action` built from data (`javascript:`, `data:`),
102
+ `window.open`, `location` assignments, redirect-after-login paths (`//host`), and
103
+ remote resources loaded from data (`<img>` in rendered markdown is an exfiltration
104
+ channel that needs no click).
105
+ - **U3. Browser token and credential handling.** Tokens accepted from the URL (any
106
+ `?token=` adopted without a `state` nonce is login CSRF / session fixation), tokens
107
+ in `localStorage` (readable by any XSS), unbounded refresh, sign-out that only
108
+ clears locally, roles parsed client-side and re-sent to the server.
109
+ - **U4. CSRF and fetch credentials.** `credentials: 'include'`, cookie auth across
110
+ origins, an API base URL taken from untrusted input, plain-`http` defaults that
111
+ carry a bearer token.
112
+ - **U5. postMessage, iframes, `window.opener`.** Message handlers without an origin
113
+ check, embedded frames, `target="_blank"` without `rel="noopener"`.
114
+ - **U6. ReDoS and expensive client-side parsing.** Regexes or parsers run on server or
115
+ stream data (unbounded SSE buffers, rescans per chunk), and user text sent to the
116
+ server as a raw regex.
117
+ - **U7. Prototype pollution and data-derived keys.** Query/filter builders that turn
118
+ user input into field paths or operators, deep merges of server data, and plain
119
+ objects indexed by server-chosen keys (`__proto__`, `constructor`) that crash renders.
120
+ - **U8. eval and dynamic code.** `eval`, `new Function` (also forces CSP `unsafe-eval`),
121
+ `import()` of computed specifiers.
122
+ - **U9. Sensitive data in client logs and storage.** `console` output, telemetry or
123
+ error reports carrying tokens or fleet data; transcripts, drafts or queued actions
124
+ persisted across logout or shared between users of one browser.
125
+ - **U10. Runtime supply chain.** Unexpected or heavy runtime dependencies, required
126
+ `peerDependencies` that are dev tools (npm 7+ installs them for every consumer),
127
+ scripts, styles or fonts loaded from a CDN, licences of shipped assets (fonts).
128
+ - **U11. SSR and Node safety.** `window`/`document`/`localStorage` touched at import
129
+ time; `dist/` ESM with extensionless or directory imports (works only in bundlers,
130
+ fails under Node, SSR and Jest); JSON exports that need `with { type: 'json' }`.
131
+ - **U12. What ships.** Tests, fixtures, test utilities importing `vitest`, compiled
132
+ examples, source maps with absolute local paths, examples using monorepo-only
133
+ aliases.
134
+
135
+ Also check per UI package:
136
+ - **Peer vs dependency.** React, `react-dom`, `@tanstack/react-query` and `zustand`
137
+ should be peers when the package shares their context or store with the host.
138
+ - **`sideEffects`.** It must match what the package does at import time (CSS imports,
139
+ singletons).
140
+ - **React peer range.** Check it is the range you intend to support.
141
+ - **Public API disclaimers.** Client-side permission helpers must say they only hide
142
+ UI and do not enforce anything.
143
+
144
+ ## Severity guide
145
+
146
+ | Severity | Meaning | Publish? |
147
+ | --- | --- | --- |
148
+ | **Critical** | Remote, unauthenticated code execution, auth bypass, or device control | Block |
149
+ | **High** | Authenticated privilege escalation, SSRF/path traversal with real reach, secret leak, a tarball that fails at runtime or ships secrets | Block |
150
+ | **Medium** | Insecure default with a safe override, DoS by an authenticated peer, missing hardening that the checklist requires | Fix before publish unless explicitly accepted |
151
+ | **Low / Info** | Defence in depth, hygiene, docs | Track |