Skip to content

Security: TheColliery/CoalMine

SECURITY.md

Verifying CoalMine

CoalMine is verified under the same framework as CoalTipple: all execution hooks follow the Phoenix-13 commandments, builds are fully reproducible from source, and security scans run on each release.


πŸ”’ Reporting a Vulnerability

Report a security issue in this repo through GitHub's private vulnerability reporting β€” Security β†’ Report a vulnerability β€” never a public issue. In scope: everything this repo ships β€” the canary skills, the shipped hooks, the installer and other scripts/, the plugin/ dist, and the PowerShell fallback hooks and platform hook-config templates we publish for manual install. Out of scope: a vulnerability in a third-party skill or codebase a canary merely scans β€” report that to its own maintainer. This is a one-person-maintained project, with no fixed response-time SLA: expect the report to be read and acknowledged, triaged against the scope above, and disclosed once a fix ships β€” or, where we decide not to fix, told that and why. A public GitHub issue remains the right channel for an ordinary, non-security bug.


πŸ”‘ 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 not signed with the maintainer key (GitHub signs these with its own), so verify a signed release tag β€” the artifact a release consumer trusts:

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

πŸ“¦ Dist Integrity

The plugin/ distribution directory is generated output gated by checks:

  • Pre-commit/Pre-push Gates: node scripts/verify.mjs automatically re-renders skills from source and byte-compares the committed output to prevent drift.
  • Reproducible Builds: Any user can clone, run node scripts/build-plugin.mjs, and verify the output is byte-identical.
  • Test Suite: node --test runs the zero-dependency unit and hermetic-hook tests (an explicit file list, wired into the git hooks).

πŸ”¬ Independent Scanning β€” NVIDIA SkillSpector

CoalMine is evaluated against NVIDIA SkillSpector, run locally via uvx (no install). Score 95/100 (CRITICAL static) β€” driven by consent-gated Self-Updating, which the static RA1 self-modification rule flags (Γ—7) as a false positive; not a defect. 12 findings, all false positives. v2.3.9 added new analyzers (incl. AR1 anti-refusal) β€” the one new finding is a context-blind match; the score is unchanged from v2.3.5 (95).

Scan provenance: SkillSpector v2.3.9 (self-reported; the tool ships no tagged releases β€” the version is the uvx-from-git HEAD, 326a2b4) Β· CoalMine v3.8.4 (commit 1cda13c) Β· 2026-07-02 Β· static stage (--no-llm). Scanning is event-driven (a new SkillSpector version, or a genuinely new attack surface) β€” this pins the last version actually verified.

  • Static Scan (95/100 - CRITICAL): 12 false positives:
    • HIGH Β· RA1 Self-Modification Γ—7 (the /coalmine:update command + the conductor's self-update scheduler + self-update comments) β€” the series consent-gated Self-Updating: the hook only SCHEDULES (no network), the agent offers the platform's own claude plugin update; the skill never rewrites its own files.
    • HIGH Β· AR1 Anti-Refusal (commands/update.md:5, new v2.3.9 analyzer) β€” matched "Always answer"; the sentence is "Always answer in the user's language" β€” a localization rule, not refuse-suppression.
    • HIGH Β· AS1 Agent Snooping (commands/stats.md:12) β€” a read-only grep of the project's own rules home for CoalMine's freshness stamps; the command ends "Do not modify any file."
    • HIGH Β· P2 Hidden Instructions (skills/gold-standard/references/method.md:1, confidence 0.21) β€” the metadata rule-freshness stamp (an instruction-shaped HTML comment carrying no command or exfil directive).
    • MED Β· EA2 Autonomous Decision (skills/gold-standard/SKILL.md:28) β€” the line reads "...never assume approval"; the scanner matched the substring "assume approval" and missed the "never." The ask_question gate is the opposite of acting without confirmation.
    • MED Β· RA2 Session Persistence (hooks/rot-canary-stop.js:240) β€” the stop-hook session temp file (written to tmpdir, deleted on stop) plus the flagged text itself: the USER's documented opt-out ("Disable: create ~/.claude/.rot-canary-off") β€” a kill-switch, not an OS-persistence mechanism.
  • 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).

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

Security is built structurally. Every hook obeys the Phoenix-13 rules (zero-dependency, no network, no child processes, fail-silent, session cleanup). No data-exfiltration path exists.

The same three Node hooks also carry an Antigravity mode (selected by the event-name argument wired in platform-configs/hooks/antigravity-hooks.json): identical Phoenix-13 posture, output restricted to a single {"injectSteps":[{"ephemeralMessage":...}]} JSON line from the conductor (the current AG PreInvocation output contract; the Stop hook emits the explicit no-op {} β€” the current engine has no Stop inject channel), and CoalMine never blocks on Antigravity.

There aren't any published security advisories