mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-11-09 22:13:39 +09:00
* dream(security): #TBD bind ADR-377 caller-identity verification into live authorizeMcpTool chokepoint (evaluated, ACCEPT-with-caveats)
authorizeMcpTool() trusted the plain, unsigned CLAUDE_FLOW_PRINCIPAL_ID env
var as caller identity with zero verification (OWASP ASI07-class gap).
ADR-377 Phase 3 already implemented Ed25519 issueInvocationToken/
verifyInvocationToken but never wired it into a live dispatch path.
Binds the two: DualModeOrchestrator mints a per-worker signed
InvocationToken at spawn (worker-lifetime TTL, wildcard tool scope --
disclosed reduction from the primitive's original per-call design);
authorizeMcpTool verifies it before trusting identity, failing closed on
missing/forged/expired tokens. Off by default (CLAUDE_FLOW_MCP_CALLER_AUTH).
6 new deterministic Vitest scenarios plus an independent adversarial
critique (fresh session, verdict CONFIRMED-SAFE-WITH-CAVEATS) are recorded
in docs/dream-cycle/dream-gist-2026-08-26.md. Darwin skipped (scope
mismatch -- binary crypto gate, no tunable parameter space).
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015bfVASxkNXKpZbMSLhVU1L
* fix(ci): register ADR-377 Phase 3 caller-identity env vars as known escape hatches
CLAUDE_FLOW_MCP_CALLER_PUBKEY and CLAUDE_FLOW_MCP_INVOCATION_TOKEN
(DualModeOrchestrator's per-worker Ed25519 credential pair, read by
resolveMcpCallerIdentity()) weren't registered in
audit-env-var-precedence.mjs's KNOWN_ESCAPE_HATCHES, so the audit flagged
CLAUDE_FLOW_MCP_CALLER_PUBKEY as a real violation (exit 1). Same no-CLI-flag
reasoning as the existing CLAUDE_FLOW_PRINCIPAL_ID entry: these are
credentials minted into a spawned worker's own environment, not a value
any caller should be able to select via a flag.
Verified: audit-env-var-precedence.mjs now exits 0. policy-runtime.test.ts
still 18/18.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01RYP825phHMjPRmmjkcAWpq
* fix(ci): regenerate root package-lock.json for codex's new @claude-flow/security dep
The CI Test Suite job runs plain `npm ci` at repo root (no v3 pnpm
install step), so it resolves workspace deps strictly from
package-lock.json — not from v3/pnpm-lock.yaml, which this PR had
already updated. codex/package.json's new @claude-flow/security
dependency was missing from package-lock.json's codex entry, so CI's
npm ci never linked it and every dual-mode test importing
orchestrator.ts failed with "Cannot find package '@claude-flow/security'".
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01RYP825phHMjPRmmjkcAWpq
* fix(ci): build @claude-flow/security before Test Suite runs it
Complements d492ea835 (codex's package-lock.json entry) rather than
duplicating it: that commit fixed `npm ci` not *linking*
@claude-flow/security for codex at all ("Cannot find package"); this
fixes the fact that even where it IS linked (codex now, @claude-flow/cli
already), nothing builds its dist/ before tests run, so importers hit
ERR_MODULE_NOT_FOUND on dist/index.js instead.
This was already a known, pre-existing gap for @claude-flow/cli:
v3/@claude-flow/cli/__tests__/policy-runtime.test.ts has carried a
scripts/ci-test-baseline.txt entry for exactly this reason since before
this PR existed. dual-mode.test.ts and dual-mode-stdin-2947.test.ts
(added by the caller-identity candidate on this branch) newly trip the
same gap in @claude-flow/codex, confirmed by diffing main's own Test
Suite ratchet failures (3, pre-existing, unrelated oauth/publisher
plugin tests) against this branch's (5: the same 3 plus these 2). Adding
new files to ci-test-baseline.txt to paper over this is explicitly
forbidden by that file's own header ("Never add entries to make a
regression green"), and gutting the tests to avoid the import would
remove real coverage of the orchestrator/security integration point.
Real fix: build @claude-flow/security before "Run all tests", using its
own existing `npm run build` (tsc && verify-oauth-exports.mjs). Verified
locally end-to-end by removing both dist/ and the stale
tsconfig.tsbuildinfo (simulating a fresh CI checkout, since both are
gitignored) -- the build step produces a full dist/, both new codex test
files pass, and (bonus, explicitly allowed by the baseline file's own
"remove entries when fixed" rule) the pre-existing policy-runtime.test.ts
baseline entry is now consistently green too, so it's removed here.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_015bfVASxkNXKpZbMSLhVU1L
---------
Co-authored-by: Claude <noreply@anthropic.com>
@claude-flow/security
Comprehensive security module for Claude Flow V3 - CVE fixes, input validation, path security, and secure credential management.
Features
- CVE Remediation - Fixes for CVE-2 (Weak Password Hashing), CVE-3 (Hardcoded Credentials), HIGH-1 (Command Injection), HIGH-2 (Path Traversal)
- Password Hashing - Secure bcrypt-based password hashing with configurable rounds (12+ recommended)
- Credential Generation - Cryptographically secure credential and API key generation
- Safe Command Execution - Allowlist-based command execution preventing injection attacks
- Path Validation - Protection against path traversal and symlink attacks
- Input Validation - Zod-based schema validation for all input types
- Token Generation - Secure token creation with HMAC signing
Installation
npm install @claude-flow/security
Standalone use (without the Ruflo CLI)
This is a plain library — every primitive (PasswordHasher,
PathValidator, SafeExecutor, InputValidator, CredentialGenerator)
is independently importable. No CLI, no MCP server, no daemon. The
primitives close CVE-2 (weak hashing), CVE-3 (default credentials),
HIGH-1 (command injection), and HIGH-2 (path traversal) — drop them
into any Node app that needs to validate at a system boundary.
Recipe — Validate input, hash a password, generate an API key
// recipe.mjs
import {
InputValidator,
EmailSchema,
PasswordHasher,
createCredentialGenerator,
} from '@claude-flow/security';
// 1. Validate user input at the boundary (Zod schemas, no surprises)
const email = InputValidator.validate(EmailSchema, 'user@example.com');
// ↳ throws if invalid; returns the typed value otherwise
// 2. Hash a password with bcrypt at the recommended cost (CVE-2)
// Default policy: ≥8 chars, ≥1 upper, ≥1 lower, ≥1 digit.
// Tune with new PasswordHasher({ rounds, requireUppercase, ... }).
const hasher = new PasswordHasher({ rounds: 12 });
const hash = await hasher.hash('CorrectHorseBatteryStaple9');
const ok = await hasher.verify('CorrectHorseBatteryStaple9', hash); // true
// 3. Generate a high-entropy API key (CVE-3) — uses crypto.randomBytes
// under the hood and refuses to emit keys below 32 bytes of entropy.
const creds = createCredentialGenerator();
const apiKey = creds.generateApiKey('ck_live_');
console.log(apiKey.keyId, apiKey.key.slice(0, 16) + '…');
// → 7e2b1a9c-… ck_live_xX9aQ…
Recipe — Refuse command injection + path traversal
import {
createDevelopmentExecutor,
createProjectPathValidator,
} from '@claude-flow/security';
// SafeExecutor — only the allow-listed commands ever run (HIGH-1)
const exec = createDevelopmentExecutor({ projectRoot: process.cwd() });
const { stdout } = await exec.execute('git', ['status', '--porcelain']);
// PathValidator — refuses traversal and symlinks out of the project (HIGH-2)
const paths = createProjectPathValidator(process.cwd());
const result = await paths.validate('../../etc/passwd');
if (!result.isValid) console.log('blocked:', result.errors.join('; '));
// → blocked: Path traversal pattern detected
Quick Start
import { createSecurityModule } from '@claude-flow/security';
// Create a complete security module
const security = createSecurityModule({
projectRoot: '/workspaces/project',
hmacSecret: process.env.HMAC_SECRET!,
bcryptRounds: 12,
allowedCommands: ['git', 'npm', 'node']
});
// Hash a password
const hash = await security.passwordHasher.hash('userPassword123');
// Validate a path
const pathResult = await security.pathValidator.validate('/workspaces/project/src/file.ts');
// Execute command safely
const output = await security.safeExecutor.execute('git', ['status']);
// Generate secure credentials
const creds = await security.credentialGenerator.generate();
API Reference
Password Hashing (CVE-2 Fix)
import { PasswordHasher, createPasswordHasher } from '@claude-flow/security';
const hasher = createPasswordHasher({ rounds: 12 });
// Hash password
const hash = await hasher.hash('password');
// Verify password
const isValid = await hasher.verify('password', hash);
// Check if hash needs rehashing
const needsRehash = hasher.needsRehash(hash);
Credential Generation (CVE-3 Fix)
import { CredentialGenerator, generateCredentials } from '@claude-flow/security';
const generator = new CredentialGenerator();
// Generate API key
const apiKey = await generator.generateApiKey({
prefix: 'cf',
length: 32
});
// Generate complete credentials
const creds = generateCredentials({
includeApiKey: true,
includeSecret: true
});
Safe Command Execution (HIGH-1 Fix)
import { SafeExecutor, createDevelopmentExecutor } from '@claude-flow/security';
const executor = createDevelopmentExecutor();
// Execute allowed command
const result = await executor.execute('git', ['status']);
// With timeout
const result2 = await executor.execute('npm', ['install'], {
timeout: 60000,
cwd: '/workspaces/project'
});
Path Validation (HIGH-2 Fix)
import { PathValidator, createProjectPathValidator } from '@claude-flow/security';
const validator = createProjectPathValidator('/workspaces/project');
// Validate path
const result = await validator.validate('../../../etc/passwd');
// { valid: false, reason: 'Path traversal detected' }
// Safe path
const result2 = await validator.validate('/workspaces/project/src/index.ts');
// { valid: true, normalized: '/workspaces/project/src/index.ts' }
Input Validation
import {
InputValidator,
SafeStringSchema,
EmailSchema,
PasswordSchema,
SpawnAgentSchema
} from '@claude-flow/security';
// Validate email
const email = EmailSchema.parse('user@example.com');
// Validate password
const password = PasswordSchema.parse('SecurePass123!');
// Validate agent spawn request
const agentRequest = SpawnAgentSchema.parse({
type: 'coder',
name: 'code-agent-1'
});
// Sanitize HTML
import { sanitizeHtml } from '@claude-flow/security';
const safe = sanitizeHtml('<script>alert("xss")</script>Hello');
// 'Hello'
Token Generation
import { TokenGenerator, quickGenerate } from '@claude-flow/security';
const generator = new TokenGenerator({
hmacSecret: process.env.HMAC_SECRET!
});
// Generate signed token
const token = await generator.generate({
type: 'session',
expiresIn: 3600
});
// Verify token
const verified = await generator.verify(token);
// Quick generation
const sessionToken = quickGenerate.sessionToken();
const verificationCode = quickGenerate.verificationCode();
Security Constants
import {
MIN_BCRYPT_ROUNDS, // 12
MAX_BCRYPT_ROUNDS, // 14
MIN_PASSWORD_LENGTH, // 8
MAX_PASSWORD_LENGTH, // 72 (bcrypt limit)
DEFAULT_TOKEN_EXPIRATION, // 3600 (1 hour)
DEFAULT_SESSION_EXPIRATION // 86400 (24 hours)
} from '@claude-flow/security';
Security Audit
import { auditSecurityConfig } from '@claude-flow/security';
const warnings = auditSecurityConfig({
bcryptRounds: 10,
hmacSecret: 'short'
});
// ['bcryptRounds (10) below recommended minimum (12)',
// 'hmacSecret should be at least 32 characters']
Validation Schemas
| Schema | Description |
|---|---|
SafeStringSchema |
Basic safe string with length limits |
IdentifierSchema |
Alphanumeric identifiers |
FilenameSchema |
Safe filenames |
EmailSchema |
Email addresses |
PasswordSchema |
Secure passwords |
UUIDSchema |
UUID v4 format |
HttpsUrlSchema |
HTTPS URLs only |
SemverSchema |
Semantic versions |
PortSchema |
Valid port numbers |
IPv4Schema |
IPv4 addresses |
SpawnAgentSchema |
Agent spawn requests |
TaskInputSchema |
Task definitions |
SecurityConfigSchema |
Security configuration |
Dependencies
bcrypt- Password hashingzod- Schema validation
Related Packages
- @claude-flow/shared - Shared types and utilities
- @claude-flow/swarm - Swarm coordination (secure agent spawning)
License
MIT