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.
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.
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)"The plugin/ distribution directory is generated output gated by checks:
- Pre-commit/Pre-push Gates:
node scripts/verify.mjsautomatically 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 --testruns the zero-dependency unit and hermetic-hook tests (an explicit file list, wired into the git hooks).
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:updatecommand + the conductor's self-update scheduler +self-updatecomments) β the series consent-gated Self-Updating: the hook only SCHEDULES (no network), the agent offers the platform's ownclaude 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-onlygrepof 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." Theask_questiongate is the opposite of acting without confirmation.MED Β· RA2 Session Persistence(hooks/rot-canary-stop.js:240) β the stop-hook session temp file (written totmpdir, 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).
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.