Skip to content

Security: TheColliery/CoalBoard

SECURITY.md

Verifying CoalBoard

CoalBoard is verified under the same framework as CoalMine and CoalTipple: the execution hook follows the Phoenix-13 commandments, the build is reproducible from source, and the design is security-first.


πŸ”’ Reporting a Vulnerability

Open an issue at github.com/TheColliery/CoalBoard, or request a private channel for sensitive PoC logs. We investigate promptly.


πŸ”‘ Commit & Tag Signatures

Every release tag and maintainer commit is SSH-signed (gpg.format=ssh); GitHub shows the Verified badge on them. Automated Dependabot / CI commits are unsigned by design (they carry no maintainer key), so verify a signed release tag β€” the artifact a release consumer trusts:

echo "* ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEtqTWGKhX1Dk9nZP8ns13Wl5zsO1Cz3VlTS6m1p2fP9" > coalboard_signers
git config gpg.ssh.allowedSignersFile ./coalboard_signers
git tag -v "$(git describe --tags --abbrev=0)"

πŸ“¦ Dist Integrity

The clean plugin/ distribution is generated from source by node scripts/build-plugin.mjs; node scripts/verify.mjs checks the dist is in sync, the manifest is valid, and the config schema is well-formed. node scripts/test.mjs runs the zero-dependency unit + hermetic-hook tests (the canonical runner β€” the node --test <glob> form is avoided: it breaks on Node 24, MODULE_NOT_FOUND).


πŸ”¬ Independent Scanning β€” NVIDIA SkillSpector

Last scan: CoalBoard v1.5.5 dist (commit 96c49af), on 2026-07-02, with NVIDIA SkillSpector v2.3.9 (self-reported β€” the tool ships no tagged releases; the version is the uvx-from-git HEAD, 326a2b4). Re-scan is event-driven on a NEW SkillSpector version (maintainer-commanded), NOT per CoalBoard release. A new SkillSpector version is exactly when the rules, codes, and score can move β€” v2.3.9 (vs the 2026-06-24 v2.3.5 pass) added new analyzers (AR1 anti-refusal Β· SSRF Β· rug-pull RP1-3 Β· PE4/PE5 Β· E5 Β· TM4) and reworked per-file score weighting; the 2026-07-02 re-scan returned the same all-false-positive verdict (identical finding classes and count: RA1 Γ—8 Β· EA2 Β· RA2 Β· TM1; the score eased 89 β†’ 71 from the scoring rework, not from a CoalBoard change).

Read the score in context. The static stage scored 71/100 (trend: v2.2.3 100 β†’ v2.3.1 96 β†’ v2.3.5 89 β†’ v2.3.9 71); the semantic LLM stage was not run this pass (--no-llm β€” static-only is the documented FP-prone baseline, pattern-match-based, flagging strings without the skill-contract context). Every finding was verified false-positive.

  • Static Scan (71/100 Β· all false-positive):
    • RA1 Self-Modification Γ—8 (self-update) β€” the series self-update is consent-gated: the hook only SCHEDULES (never networks), the agent offers the platform's own claude plugin update; the skill never rewrites its own files.
    • TM1 Tool-Parameter Abuse (rm -rf) β€” the matched text is the verify step's pre-run lint that BANS rm -rf in reviewed code (skip-and-flag) β€” a defensive rule, the opposite of using it.
    • RA2 Session Persistence (lens-prompt template) β€” instructs lenses to be instantiated from the canonical template and forbids injecting dev-governance β€” prompt-hygiene, not any OS/session-persistence mechanism RA2 keys on.
    • EA2 Autonomous Decision ("without asking") β€” the matched clause is "auto β†’ convene without asking", the documented user-CONFIGURED standing-consent mode (default ask); the hard rules below force report-only with no human present and REFUSE gateless auto-apply.
  • Method: uvx --from git+https://github.com/NVIDIA/skillspector.git skillspector scan <plugin> --format json β€” uvx fetches its own ephemeral Python, so no manual Python/pip install is needed; a JSON report is written even when the optional LLM stage is skipped.
  • LLM Semantic Scan: not run this pass (--no-llm β€” static-only is the documented, FP-prone baseline: pattern-match without the skill-contract context).

(Exact per-category counts and locations shift between SkillSpector versions β€” e.g. the RA2 match moved from the .coalboard/proposed/ staging text to the lens-template text; the categories and the all-false-positive verdict are stable.) This matches the family baseline: CoalMine and CoalTipple carry the same RA1 self-modification false positive (from consent-gated Self-Updating) β€” all-false-positive across the family; each repo's SECURITY.md pins its own last-scan score. The report JSON is not shipped.


πŸ›‘οΈ Structural Safety (Phoenix-13)

hooks/coalboard-conductor.js is advise-only and Phoenix-pure: zero dependencies (Node builtins only), no network, no child processes, fail-silent (exits 0 on any error; never crashes the host), and it only emits the two sanctioned channels. It detects and injects β€” it never spawns workers, networks, or applies anything. Its stdin parse is guarded against non-object input.


πŸ” Security by Design β€” the Board

The board is built so that reviewing untrusted work cannot harm the host:

  • The work under review is DATA, never instructions β€” the lens prompts never obey an injected "approve this".
  • Propose, never execute β€” the lenses emit a diff to .coalboard/proposed/; the board itself runs no side-effect. A real side-effect (a migration, an API call, a deploy) fires only at the human-approved apply, with a warning, and is never auto-retried.
  • Verify is contract-isolated, NOT OS-sandboxed β€” a skill cannot OS-sandbox; the judge runs reviewed checks in the staging dir with a pre-run lint (banned modules / rm -rf / network), no real DB/network where possible, and a disposable VM for genuinely hostile code. Contract-enforced + the judge's discipline, not an OS guarantee. External SAST is optional, never a hard requirement.
  • Secrets are scrubbed β€” credential patterns are scrubbed from anything logged or displayed (best-effort defense-in-depth, contract-enforced β€” NOT a guarantee a secret is caught; the staging + read-only-worker boundary is the real protection). scripts/lib/secrets.mjs is the reference scrubber + its test target β€” a DEV file, not part of the shipped plugin runtime.
  • No human, no apply β€” a non-interactive (cron/headless) run is report-only; the human consent gate is the load-bearing safety node.

There aren't any published security advisories