| Version | Supported |
|---|---|
| 3.3.x | ✅ Active |
| 3.0.x–3.2.x | ✅ Security fixes only |
| 2.3.x | ❌ End of life |
| 2.0.x | ❌ End of life |
| 1.0.x | ❌ End of life |
If you discover a security vulnerability in Specky, please report it responsibly:
- Do NOT open a public issue.
- Email paulasilvatech@github.com with:
- Description of the vulnerability
- Steps to reproduce
- Impact assessment
- Suggested fix (if any)
- You will receive an acknowledgment within 48 hours.
- A fix will be released within 7 days for critical issues.
All 58 MCP tool inputs are validated using Zod schemas with .strict() mode. No unknown fields are accepted. This prevents injection of unexpected parameters through the MCP JSON-RPC interface.
AI Client → JSON-RPC → Zod .strict() validation → Service layer
FileManager (the sole file I/O service) sanitizes all paths before any filesystem operation:
- Resolves paths relative to the workspace root
- Rejects paths containing
..sequences - Blocks access outside the designated workspace directory
- All file operations are scoped to
SDD_WORKSPACEor the current working directory
Specky does not use eval(), Function(), vm.runInNewContext(), or any dynamic code execution. Template rendering uses string replacement only — no template engines that execute code.
Specky operates entirely locally. It makes zero outbound network requests. All data stays on the user's machine. The MCP server communicates only via stdio (JSON-RPC over stdin/stdout) or optional HTTP transport on localhost.
Specky has only 3 runtime dependencies:
| Dependency | Purpose | Security Profile |
|---|---|---|
@modelcontextprotocol/sdk |
MCP protocol implementation | Official SDK from Anthropic |
zod |
Input schema validation | Zero dependencies, widely audited |
yaml |
Project configuration parsing | Focused parser used for .specky/config.yml |
Runtime dependencies are kept intentionally small and are audited in CI.
- All log output goes to stderr — stdout is reserved for JSON-RPC protocol messages
- No sensitive data (credentials, tokens, file contents) is included in log messages
- Audit-relevant tool invocations are recorded only in the local
.specs/directory
| OWASP Category | Mitigation |
|---|---|
| A01 Broken Access Control | Path sanitization in FileManager; workspace-scoped operations |
| A02 Cryptographic Failures | No cryptographic operations; no secrets handling |
| A03 Injection | Zod .strict() validation on all inputs; no SQL/eval/shell execution |
| A04 Insecure Design | State machine enforces phase ordering; thin tools / fat services separation |
| A05 Security Misconfiguration | Minimal config surface; no default credentials; no admin endpoints |
| A06 Vulnerable Components | 3 runtime deps only; Dependabot enabled; regular audits |
| A07 Authentication Failures | No authentication layer (local tool); MCP transport handles auth |
| A08 Data Integrity Failures | Atomic file writes via FileManager; Zod schema enforcement |
| A09 Logging Failures | Structured stderr logging; no stdout pollution |
| A10 SSRF | Zero outbound network requests |
# Check for known vulnerabilities
npm audit
# Check for outdated dependencies
npm outdatedWe run npm audit in CI on every pull request. Any high or critical vulnerability blocks the merge.
| Variable | Purpose | Default |
|---|---|---|
SDD_WORKSPACE |
Restricts file operations to this directory | Current working directory |
PORT |
HTTP transport port (when using --http mode) |
3200 |
When using HTTP transport mode (--http), bind to localhost only. Do not expose Specky to public networks without an authentication proxy.
- TypeScript
strictmode enabled — no implicitany, no unchecked index access - Zero
anytypes in source code — enforced by CI - All schemas use
.strict()— rejects unknown fields FileManageris the sole I/O boundary — no directfscalls in tools or other services- No shell command execution — branch names and PR payloads are data only, not executed
| Practice | Details |
|---|---|
| Use stdio mode by default | specky-sdd (global install) — no network exposure, process-level isolation |
| Never expose HTTP mode publicly | --http mode has no authentication or TLS. If you need remote access, place behind a reverse proxy (nginx, Caddy, Traefik) with TLS and authentication |
Protect .specs/ directory |
Contains architecture details, API contracts, security models. Add to .gitignore for sensitive projects, or use a private repository |
Protect .checkpoints/ |
Contains full copies of all spec artifacts. Treat like source code |
| Keep security-scan hook active | .claude/hooks/security-scan.sh scans for hardcoded secrets and blocks commits (exit 2). Do not disable |
| Review auto-generated specs | sdd_turnkey_spec and sdd_auto_pipeline generate from natural language — review before committing to ensure no sensitive details leaked |
| Use environment variables | Never write actual secrets in spec artifacts. Reference them as $VAR_NAME |
Run npm audit regularly |
Catches dependency vulnerabilities in runtime and development dependencies |
If you must use HTTP mode (--http):
1. [ ] Bind to localhost only (default behavior)
2. [ ] Place behind reverse proxy with TLS (HTTPS)
3. [ ] Add authentication to the reverse proxy
4. [ ] Set firewall rules to restrict access
5. [ ] Use a unique PORT via environment variable
6. [ ] Monitor access logs on the reverse proxy
Example secure deployment with nginx:
server {
listen 443 ssl;
server_name specky.internal.company.com;
ssl_certificate /etc/ssl/certs/specky.crt;
ssl_certificate_key /etc/ssl/private/specky.key;
# Require authentication
auth_basic "Specky MCP Server";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:3200;
proxy_set_header Host $host;
}
}| Data | Classification | Storage | Protection |
|---|---|---|---|
| CONSTITUTION.md | Internal | .specs/ |
Filesystem permissions |
| SPECIFICATION.md | Business Confidential | .specs/ |
May contain business logic — review before sharing |
| DESIGN.md | Confidential | .specs/ |
Contains architecture, API contracts, security model |
| TASKS.md | Internal | .specs/ |
Implementation plan |
| .checkpoints/*.json | Confidential | .specs/.checkpoints/ |
Full artifact snapshots |
| .sdd-state.json | Internal | .specs/ |
Pipeline metadata only |
| docs/journey-*.md | Business Confidential | docs/ |
Complete audit trail |
| Routing payloads | Transient | Memory only | Never persisted by Specky |
These guarantees describe the intended product boundary. Known implementation gaps are tracked in docs/DETERMINISM.md and docs/ENTERPRISE-CONTROLS.md.
- No outbound network calls from core MCP tools — optional external MCP integrations are returned as routing payloads for the AI client to execute.
- No dynamic code execution — no
eval(),Function(), orvm.runInNewContext()in the Specky core. - No credential storage by design — no API keys, tokens, or passwords are intentionally stored by Specky.
- Workspace-scoped I/O is the target boundary —
FileManager.sanitizePath()enforces this for core file operations; document import hardening is tracked as an enterprise remediation item. - No sensitive operational logging by design — logs go to stderr and should contain only operational messages.
- Explicit hook execution is administrative —
specky hooksintentionally runs installed hook scripts for diagnostics and compatibility testing.
See docs/SYSTEM-DESIGN.md for the complete security architecture with threat model.
Running npx -y specky-sdd@latest without a pinned version downloads the latest package from npm on every invocation. This creates a supply-chain exposure: a compromised npm registry entry or a typosquat could execute malicious code in your environment before Specky even starts.
Recommended mitigations (ordered by risk reduction):
| Approach | Risk reduction | Notes |
|---|---|---|
npm install -g specky-sdd@<pinned-version> + specky install |
High — fetched once, upgrades only when you explicitly run npm install -g again |
Recommended for individual developers |
npm install --save-dev specky-sdd@<pinned-version> + npx specky install |
Higher — version-pinned in package.json; package-lock.json pins transitive deps |
Best for teams (reproducible across clones) |
Offline bundle: npm pack specky-sdd@<version> + npm install ./specky-sdd-*.tgz |
Higher — no network access at install time after the initial download | Air-gapped environments |
specky doctor after install |
Defense-in-depth — verifies SHA256 of every installed file against install.lock |
Run after every install/upgrade |
Docker (ghcr.io/paulasilvatech/specky:<version>) |
Highest — immutable image by digest | Best for CI/CD and air-gapped |
Workspace isolation pattern (CI/CD):
# Install into a local vendor directory — no global write permissions needed
npm install specky-sdd@3.4.0 --prefix ./vendor --ignore-scripts
./vendor/node_modules/.bin/specky install
./vendor/node_modules/.bin/specky doctor # integrity checkCLI binary entry points (both ship in the same package):
specky— unified CLI (install,doctor,status,upgrade,hooks,serve)specky-sdd— legacy alias; with no subcommand it routes tospecky serve(MCP stdio server), preserving any existing.mcp.jsonconfigs that referencespecky-sdddirectly
Install integrity check:
Every specky install produces .specky/install.lock with SHA256 of every deployed file. specky doctor validates these hashes — a tampered hook script or agent file is detected before any agent runs.
The --ignore-scripts flag prevents npm lifecycle scripts from running during install, which is a common supply-chain attack vector.
Specky addresses the 12 threat categories from the CoSAI MCP Security White Paper:
| ID | Threat Category | Specky Mitigation |
|---|---|---|
| T-01 | Tool Poisoning | Zod .strict() on all 58 tool inputs — no unknown fields accepted |
| T-02 | Prompt Injection via Tool Results | No user-controlled data interpolated into tool responses |
| T-03 | Excessive Tool Permissions | Thin Tools pattern — each tool does exactly one operation |
| T-04 | Insecure Data Storage | FileManager enforces workspace boundary; no secrets in files |
| T-05 | Insufficient Input Validation | All inputs validated with Zod schemas before reaching service layer |
| T-06 | Uncontrolled Resource Consumption | Rate limiter (opt-in) for HTTP mode; stdio is single-session |
| T-07 | Broken Access Control | RBAC engine (opt-in) — viewer/contributor/admin roles; path sanitization |
| T-08 | Supply Chain Compromise | 3 runtime deps only; Dependabot enabled; global install recommended |
| T-09 | Credential Leakage | No secrets in logs (stderr only); no credentials in spec artifacts |
| T-10 | Insecure Communication | stdio mode has zero network exposure; HTTP mode binds to localhost |
| T-11 | State Manipulation | HMAC-SHA256 signature on .sdd-state.json; tamper detection on load |
| T-12 | Audit Trail Integrity | Hash-chained JSONL audit log; rotation; syslog/OTLP export (opt-in) |
| # | OWASP MCP Risk | Specky Mitigation |
|---|---|---|
| M1 | Prompt Injection | No dynamic content in tool descriptions; outputs are structured JSON |
| M2 | Insecure Tool Design | Thin Tools / Fat Services — tools are pure input/output wrappers |
| M3 | Excessive Agency | No shell execution, no outbound network, no code eval |
| M4 | Insufficient Authentication | HTTP mode delegates to reverse proxy; stdio is process-isolated |
| M5 | Broken Object-Level Authorization | RBAC engine enforces per-tool access by role (opt-in) |
| M6 | Sensitive Data Exposure | FileManager path boundary; no credential logging; workspace-scoped I/O |
| M7 | Insecure Plugin Composition | Fixed tool set at startup — no dynamic loading |
| M8 | Improper Error Handling | All service errors caught; tools return structured error responses |
| M9 | Insufficient Logging | Hash-chained audit trail; syslog export available |
| M10 | Vulnerable Dependencies | 3 runtime deps; npm audit in CI; Dependabot on GitHub |