@aaronjmars 1c3280dc0d
fix(security): add host/origin allowlist + validate git refs + quote workflow input (#2185)
Three defense-in-depth fixes around untrusted input flowing to subprocess execution:

1. **Control-pane HTTP server (scripts/lib/control-pane/server.js)**
   The local control-pane API binds to 127.0.0.1 but had no Host or Origin
   validation, so a DNS-rebinding attack from a malicious website could pivot
   into the loopback endpoints — including POST /api/actions/:id, which spawns
   'cargo run -- graph ...' with caller-supplied query strings. Add a hostname
   allowlist (loopback variants plus the explicitly configured --host) and
   reject mismatched Host (421) or non-loopback Origin (403) before any route
   handler runs.

2. **OpenCode git-summary tool (.opencode/tools/git-summary.ts)**
   The tool was building 'git diff ${baseBranch}...HEAD --stat' with execSync
   and a raw model-supplied baseBranch string. Switch run() to execFileSync
   with an args array (no shell), validate baseBranch against a conservative
   git-ref allowlist (rejects shell metacharacters, leading -, embedded ..),
   and clamp the depth arg to a small positive integer before interpolating
   into 'git log --oneline -<N>'.

3. **Reusable test workflow (.github/workflows/reusable-test.yml)**
   The 'Install dependencies' step interpolated ${{ inputs.package-manager }}
   directly into a bash 'case' and into an echo, so a downstream caller that
   forwarded attacker-controllable input could inject into the runner. Move
   the input into a PACKAGE_MANAGER env var and reference $PACKAGE_MANAGER
   inside the script per the GitHub script-injection guidance.

Detected by Aeon + semgrep p/security-audit (host check via threat-model
manual-review axis; git-summary via detect-child-process; workflow via
run-shell-injection).

Verification: node tests/run-all.js — 2686/2687 pre-existing tests pass; the
one failure (observe.sh legacy output fallback) reproduces on main without
this branch applied. Added 2 new control-pane tests covering the allowlist
classifier and the DNS-rebinding-gate behavior end-to-end.

---
Filed by [Aeon](https://github.com/aaronjmars/aeon-aaron).

Co-authored-by: aeonframework <aeon@aaronjmars.com>
2026-06-15 13:49:40 -04:00
..

OpenCode ECC Plugin

WARNING: This README is specific to OpenCode usage. If you installed ECC via npm (e.g. npm install opencode-ecc), refer to the root README instead.

ECC plugin for OpenCode - agents, commands, hooks, and skills.

Installation

Installation Overview

There are two ways to use ECC:

  1. npm package (recommended for most users) Install via npm/bun/yarn and use the ecc-install CLI to set up rules and agents.

  2. Direct clone / plugin mode Clone the repository and run OpenCode directly inside it.

Choose the method that matches your workflow below.

Option 1: npm Package

npm install ecc-universal

Add to your opencode.json:

{
  "plugin": ["ecc-universal"]
}

This loads the ECC OpenCode plugin module from npm:

  • hook/event integrations
  • bundled custom tools exported by the plugin

It does not auto-register the full ECC command/agent/instruction catalog in your project config. For the full OpenCode setup, either:

  • run OpenCode inside this repository, or
  • copy the relevant .opencode/commands/, .opencode/prompts/, .opencode/instructions/, and the instructions, agent, and command config entries into your own project

After installation, the ecc-install CLI is also available:

npx ecc-install typescript

Option 2: Direct Use

Clone and run OpenCode in the repository:

git clone https://github.com/affaan-m/ECC
cd ECC
opencode

If you also want to apply the ECC home install (node scripts/install-apply.js --target opencode --profile full), build the plugin first so the compiled payload at .opencode/dist/ exists:

node scripts/build-opencode.js   # or: npm run build:opencode
node scripts/install-apply.js --target opencode --profile full

Without .opencode/dist/index.js, OpenCode will detect the slash commands but silently skip plugin hooks and tools. The installer now fails fast with a pointer to this command if the build step is missing.

Features

Agents (12)

Agent Description
planner Implementation planning
architect System design
code-reviewer Code review
security-reviewer Security analysis
tdd-guide Test-driven development
build-error-resolver Build error fixes
e2e-runner E2E testing
doc-updater Documentation
refactor-cleaner Dead code cleanup
go-reviewer Go code review
go-build-resolver Go build errors
database-reviewer Database optimization

Commands (31)

Command Description
/plan Create implementation plan
/tdd TDD workflow
/code-review Review code changes
/security Security review
/build-fix Fix build errors
/e2e E2E tests
/refactor-clean Remove dead code
/orchestrate Multi-agent workflow
/learn Extract patterns
/checkpoint Save progress
/verify Verification loop
/eval Evaluation
/update-docs Update docs
/update-codemaps Update codemaps
/test-coverage Coverage analysis
/setup-pm Package manager
/go-review Go code review
/go-test Go TDD
/go-build Go build fix
/skill-create Generate skills
/instinct-status View instincts
/instinct-import Import instincts
/instinct-export Export instincts
/evolve Cluster instincts
/promote Promote project instincts
/projects List known projects
/harness-audit Audit harness reliability and eval readiness
/loop-start Start controlled agentic loops
/loop-status Check loop state and checkpoints
/quality-gate Run quality gates on file/repo scope
/model-route Route tasks by model and budget

Plugin Hooks

Hook Event Purpose
Prettier file.edited Auto-format JS/TS
TypeScript tool.execute.after Check for type errors
console.log file.edited Warn about debug statements
Notification session.idle Desktop notification
Security tool.execute.before Check for secrets

Custom Tools

Tool Description
run-tests Run test suite with options
check-coverage Analyze test coverage
security-audit Security vulnerability scan

Hook Event Mapping

OpenCode's plugin system maps to Claude Code hooks:

Claude Code OpenCode
PreToolUse tool.execute.before
PostToolUse tool.execute.after
Stop session.idle
SessionStart session.created
SessionEnd session.deleted

OpenCode has 20+ additional events not available in Claude Code.

Hook Runtime Controls

OpenCode plugin hooks honor the same runtime controls used by Claude Code/Cursor:

export ECC_HOOK_PROFILE=standard
export ECC_DISABLED_HOOKS="pre:bash:tmux-reminder,post:edit:typecheck"
  • ECC_HOOK_PROFILE: minimal, standard (default), strict
  • ECC_DISABLED_HOOKS: comma-separated hook IDs to disable

Skills

The default OpenCode config loads 11 curated ECC skills via the instructions array:

  • coding-standards
  • backend-patterns
  • frontend-patterns
  • frontend-slides
  • security-review
  • tdd-workflow
  • strategic-compact
  • eval-harness
  • verification-loop
  • api-design
  • e2e-testing

Additional specialized skills are shipped in skills/ but not loaded by default to keep OpenCode sessions lean:

  • article-writing
  • content-engine
  • market-research
  • investor-materials
  • investor-outreach

Configuration

Full configuration in opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5",
  "small_model": "anthropic/claude-haiku-4-5",
  "plugin": ["./plugins"],
  "instructions": [
    "skills/tdd-workflow/SKILL.md",
    "skills/security-review/SKILL.md"
  ],
  "agent": { /* 12 agents */ },
  "command": { /* 24 commands */ }
}

License

MIT