claude-flow-novice 2.15.3 → 2.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/.claude/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/.claude/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/.claude/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/.claude/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/.claude/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/.claude/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/.claude/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/.claude/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/.claude/commands/cfn-loop-cli.md +29 -6
- package/.claude/commands/switch-api.md +31 -10
- package/.claude/hooks/cfn-lint-sql-injection.sh +61 -0
- package/.claude/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/.claude/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +238 -29
- package/.claude/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/.claude/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/.claude/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/.claude/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/.claude/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/.claude/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/.claude/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/.claude/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/.claude/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/.claude/skills/cfn-redis-coordination/redis-functions.sh +34 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/.claude/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/.claude/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/.claude/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/.claude/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/.claude/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/.claude/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/README.md +116 -475
- package/claude-assets/agents/cfn-dev-team/README.md +103 -0
- package/claude-assets/agents/cfn-dev-team/architecture/goal-planner.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +355 -6
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +82 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +77 -15
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +99 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +1 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +20 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +97 -0
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +110 -13
- package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +106 -15
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +115 -11
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +94 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +87 -9
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +85 -7
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +160 -28
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +101 -19
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +108 -14
- package/claude-assets/agents/cfn-dev-team/reviewers/{reviewer.md → code-reviewer.md} +95 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +107 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +98 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +95 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +136 -9
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +108 -1
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +107 -13
- package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +737 -0
- package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
- package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +828 -0
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +106 -7
- package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +77 -0
- package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +684 -0
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +110 -1
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +94 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +87 -13
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +103 -7
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -3
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +94 -7
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +46 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
- package/claude-assets/cfn-extras/skills/advanced-features/cfn-agent-swap/recommend-swap.sh +59 -59
- package/claude-assets/cfn-extras/skills/analytics/cfn-improvement-recommender/recommend-improvements.sh +91 -91
- package/claude-assets/cfn-extras/skills/analytics/cfn-pattern-extraction/extract-patterns.sh +79 -79
- package/claude-assets/cfn-extras/skills/analytics/cfn-retrospective-report/generate-report.sh +100 -100
- package/claude-assets/cfn-extras/skills/analytics/cfn-telemetry/start-telemetry.sh +110 -110
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/add-bullet.sh +145 -145
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/log-merge.sh +67 -67
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/monitor-injection-performance.sh +137 -137
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/optimize-injection-pipeline.sh +168 -168
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/query-reflections.sh +35 -35
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/store-reflection.sh +45 -45
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/track-ab-test.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-ace-system/update-reflection.sh +41 -41
- package/claude-assets/cfn-extras/skills/deprecated/cfn-cli-setup/validate-cli-environment.sh +191 -191
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/create-campaign.sh +231 -231
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/get-campaign-performance.sh +190 -190
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/pause-campaign.sh +142 -142
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/set-budget.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-ad-campaigns/operations/update-bid-strategy.sh +133 -133
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/get-conversation-history.sh +121 -121
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/qualify-lead.sh +156 -156
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/schedule-demo.sh +181 -181
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/send-message.sh +137 -137
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-chatbot-conversations/operations/transfer-to-human.sh +179 -179
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/create-campaign.sh +183 -183
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/get-delivery-status.sh +139 -139
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/opt-out.sh +150 -150
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/schedule-campaign.sh +187 -187
- package/claude-assets/cfn-extras/skills/marketing/cfn-marketing-sms-campaigns/operations/send-sms.sh +181 -181
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/test-web-portal-skill.sh +50 -50
- package/claude-assets/cfn-extras/skills/ui-portal/cfn-web-portal/validate-deployment.sh +84 -84
- package/claude-assets/cfn-extras/skills/utility/cfn-environment-sanitization/sanitize-environment.sh +243 -243
- package/claude-assets/commands/cfn-loop-cli.md +29 -6
- package/claude-assets/commands/switch-api.md +31 -10
- package/claude-assets/hooks/cfn-lint-sql-injection.sh +61 -0
- package/claude-assets/hooks/cfn-post-edit-cfn-retrospective.sh +33 -2
- package/claude-assets/hooks/cfn-pre-edit-security-warning.sh +40 -0
- package/claude-assets/hooks/detect-hardcoded-credentials.sh +212 -0
- package/claude-assets/skills/SKILL_TEMPLATE.md +774 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +84 -113
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +33 -6
- package/claude-assets/skills/agent-template-generator/SKILL.md +440 -0
- package/claude-assets/skills/agent-template-generator/generate-agent.sh +405 -0
- package/claude-assets/skills/agent-validation-linter/SKILL.md +589 -0
- package/claude-assets/skills/agent-validation-linter/lint-agents.sh +271 -0
- package/claude-assets/skills/bootstrap/bash-fundamentals.md +786 -0
- package/claude-assets/skills/bootstrap/database-connection.md +464 -0
- package/claude-assets/skills/bootstrap/error-handling.md +580 -0
- package/claude-assets/skills/bootstrap/file-operations.md +699 -0
- package/claude-assets/skills/bootstrap/skill-loader.md +616 -0
- package/claude-assets/skills/bootstrap/sqlite-params.sh +287 -0
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh +22 -24
- package/claude-assets/skills/cfn-automatic-memory-persistence/test-memory-persistence.sh +17 -16
- package/claude-assets/skills/cfn-deployment/SKILL.md +293 -0
- package/claude-assets/skills/cfn-deployment/execute.sh +21 -0
- package/claude-assets/skills/cfn-docker-agent-spawning/SKILL.md +28 -4
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +3 -1
- package/claude-assets/skills/cfn-docker-loop-orchestration/orchestrate.sh +224 -20
- package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +38 -0
- package/claude-assets/skills/cfn-error-batching-strategy/lib/core-functions.sh +47 -47
- package/claude-assets/skills/cfn-file-operations/SKILL.md +290 -0
- package/claude-assets/skills/cfn-file-operations/execute.sh +129 -0
- package/claude-assets/skills/cfn-file-operations/lib/atomic-write.sh +294 -0
- package/claude-assets/skills/cfn-file-operations/lib/lock.sh +361 -0
- package/claude-assets/skills/cfn-file-operations/test.sh +369 -0
- package/claude-assets/skills/cfn-log-operations/SKILL.md +308 -0
- package/claude-assets/skills/cfn-log-operations/execute.sh +420 -0
- package/claude-assets/skills/cfn-log-operations/lib/rotate.sh +406 -0
- package/claude-assets/skills/cfn-log-operations/lib/search.sh +448 -0
- package/claude-assets/skills/cfn-log-operations/test.sh +394 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +550 -46
- package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +277 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +238 -29
- package/claude-assets/skills/cfn-loop-orchestration/security_utils.sh +24 -0
- package/claude-assets/skills/cfn-loop-orchestration/test-iteration-context-injection.sh +366 -0
- package/claude-assets/skills/cfn-parameterized-queries/SKILL.md +339 -0
- package/claude-assets/skills/cfn-playbook/query-playbook.sh +19 -15
- package/claude-assets/skills/cfn-playbook/update-playbook.sh +25 -14
- package/claude-assets/skills/cfn-process-instrumentation/instrument-process.sh +44 -0
- package/claude-assets/skills/cfn-promotion/SKILL.md +305 -0
- package/claude-assets/skills/cfn-redis-coordination/CENTRALIZED_REDIS_WRAPPER.md +319 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-log.sh.bak +124 -0
- package/claude-assets/skills/cfn-redis-coordination/agent-recovery.sh +2 -2
- package/claude-assets/skills/cfn-redis-coordination/collect-confidence-scores.sh +30 -0
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +33 -0
- package/claude-assets/skills/cfn-redis-coordination/get-success-criteria.sh +54 -0
- package/claude-assets/skills/cfn-redis-coordination/invoke-waiting-mode.sh +6 -2
- package/claude-assets/skills/cfn-redis-coordination/redis-cli-wrapper.sh +24 -3
- package/claude-assets/skills/cfn-redis-coordination/redis-functions.sh +34 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +24 -31
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +4 -0
- package/claude-assets/skills/cfn-redis-coordination/store-success-criteria.sh +85 -0
- package/claude-assets/skills/cfn-redis-coordination/update-all-scripts.sh +67 -0
- package/claude-assets/skills/cfn-skill-loader/SKILL.md +466 -0
- package/claude-assets/skills/cfn-skill-loader/execute.sh +344 -0
- package/claude-assets/skills/cfn-sqlite-memory/ttl-cleanup.sh +17 -25
- package/claude-assets/skills/cfn-task-audit/get-audit-data.sh +42 -21
- package/claude-assets/skills/cfn-task-audit/store-task-audit.sh +17 -10
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh +17 -14
- package/claude-assets/skills/cfn-test-runner/detect-regressions.sh.backup-1763392821 +55 -0
- package/claude-assets/skills/cfn-test-runner/store-benchmarks.sh +17 -19
- package/claude-assets/skills/cfn-transparency-middleware/test-e2e.sh +15 -0
- package/claude-assets/skills/cfn-transparency-middleware/tests/input-validation.sh +15 -0
- package/claude-assets/skills/cfn-utilities/SKILL.md +237 -0
- package/claude-assets/skills/cfn-utilities/execute.sh +32 -0
- package/claude-assets/skills/cfn-utilities/lib/errors.sh +56 -0
- package/claude-assets/skills/cfn-utilities/lib/file-ops.sh +164 -0
- package/claude-assets/skills/cfn-utilities/lib/logging.sh +77 -0
- package/claude-assets/skills/cfn-utilities/lib/retry.sh +127 -0
- package/claude-assets/skills/cfn-utilities/test.sh +317 -0
- package/claude-assets/skills/integration/agent-handoff.sh +62 -64
- package/claude-assets/skills/json-validation/SKILL.md +431 -0
- package/claude-assets/skills/json-validation/test-validate-success-criteria.sh +421 -0
- package/claude-assets/skills/json-validation/validate-success-criteria.sh +197 -0
- package/claude-assets/skills/redis-coordination/validate-parameters.sh +34 -0
- package/claude-assets/skills/workflow-codification/DEPLOY_QUICK_REFERENCE.md +106 -0
- package/claude-assets/skills/workflow-codification/PROPAGATE_UPDATE_QUICK_REFERENCE.md +366 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh +481 -0
- package/claude-assets/skills/workflow-codification/deploy-approved-skill.sh.backup-1763392820 +512 -0
- package/claude-assets/skills/workflow-codification/lib/security-utils.sh +204 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh +648 -0
- package/claude-assets/skills/workflow-codification/propagate-skill-update.sh.backup-1763392820 +664 -0
- package/claude-assets/skills/workflow-codification/test-integration.sh +15 -0
- package/claude-assets/skills/workflow-codification/test-metadata-update.sh +350 -0
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh +55 -14
- package/claude-assets/skills/workflow-codification/track-cost-savings.sh.backup-1763392821 +445 -0
- package/claude-assets/skills/workflow-codification/track-edge-case.sh +27 -60
- package/claude-assets/skills/workflow-codification/workflow-codification.db +0 -0
- package/dist/ace/ace-curator.js +10 -2
- package/dist/ace/ace-curator.js.map +1 -1
- package/dist/ace/ace-generator.js +4 -0
- package/dist/ace/ace-generator.js.map +1 -1
- package/dist/ace/ace-reflector.js +1 -1
- package/dist/ace/ace-reflector.js.map +1 -1
- package/dist/ace/context-injection.js +24 -2
- package/dist/ace/context-injection.js.map +1 -1
- package/dist/agents/task-agent-integration.js +1 -1
- package/dist/agents/task-agent-integration.js.map +1 -1
- package/dist/api/health-endpoints.js +390 -0
- package/dist/api/health-endpoints.js.map +1 -0
- package/dist/cli/agent-executor.js +4 -1
- package/dist/cli/agent-executor.js.map +1 -1
- package/dist/cli/agent-prompt-builder.js +89 -1
- package/dist/cli/agent-prompt-builder.js.map +1 -1
- package/dist/cli/agent-spawn.js +130 -37
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/config-manager.js +109 -91
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/conversation-fork-cleanup.js +201 -0
- package/dist/cli/conversation-fork-cleanup.js.map +1 -0
- package/dist/cli/conversation-fork.js +16 -3
- package/dist/cli/conversation-fork.js.map +1 -1
- package/dist/cli/skill-cache-validator.js +412 -0
- package/dist/cli/skill-cache-validator.js.map +1 -0
- package/dist/cli/skill-cli.js +991 -0
- package/dist/cli/skill-cli.js.map +1 -0
- package/dist/cli/skill-execution-logger.js +284 -0
- package/dist/cli/skill-execution-logger.js.map +1 -0
- package/dist/cli/skill-loader.js +457 -0
- package/dist/cli/skill-loader.js.map +1 -0
- package/dist/coordination/event-bus.js +2 -2
- package/dist/coordination/event-bus.js.map +1 -1
- package/dist/coordination/fleet-manager.js +1 -1
- package/dist/coordination/fleet-manager.js.map +1 -1
- package/dist/coordination/index.js +23 -9
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/types/fleet-manager.types.js.map +1 -1
- package/dist/db/migration-manager.js +483 -0
- package/dist/db/migration-manager.js.map +1 -0
- package/dist/db/skills-query.js +535 -0
- package/dist/db/skills-query.js.map +1 -0
- package/dist/integration/DatabaseHandoff.js +1 -1
- package/dist/integration/DatabaseHandoff.js.map +1 -1
- package/dist/jobs/edge-case-analyzer.js +367 -0
- package/dist/jobs/edge-case-analyzer.js.map +1 -0
- package/dist/jobs/promotion-sla-enforcer.js +288 -0
- package/dist/jobs/promotion-sla-enforcer.js.map +1 -0
- package/dist/lib/agent-output-parser.js.map +1 -1
- package/dist/lib/agent-output-validator.js.map +1 -1
- package/dist/lib/agent-workspace.js +281 -0
- package/dist/lib/agent-workspace.js.map +1 -0
- package/dist/lib/atomic-file-writer.js +377 -0
- package/dist/lib/atomic-file-writer.js.map +1 -0
- package/dist/lib/backup-manager.js +779 -0
- package/dist/lib/backup-manager.js.map +1 -0
- package/dist/lib/checkpoint-manager.js +837 -0
- package/dist/lib/checkpoint-manager.js.map +1 -0
- package/dist/lib/circuit-breaker.js +340 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/completion-signal-handler.js +243 -0
- package/dist/lib/completion-signal-handler.js.map +1 -0
- package/dist/lib/config-manager.js +312 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/config-migrator.js +386 -0
- package/dist/lib/config-migrator.js.map +1 -0
- package/dist/lib/config-validator.js.map +1 -1
- package/dist/lib/correlation-cache.js +311 -0
- package/dist/lib/correlation-cache.js.map +1 -0
- package/dist/lib/correlation.js +263 -0
- package/dist/lib/correlation.js.map +1 -0
- package/dist/lib/database-service/connection-pool-manager.js +520 -0
- package/dist/lib/database-service/connection-pool-manager.js.map +1 -0
- package/dist/lib/database-service/correlation.js +329 -0
- package/dist/lib/database-service/correlation.js.map +1 -0
- package/dist/lib/database-service/errors.js +120 -0
- package/dist/lib/database-service/errors.js.map +1 -0
- package/dist/lib/database-service/index.js +168 -0
- package/dist/lib/database-service/index.js.map +1 -0
- package/dist/lib/database-service/postgres-adapter.js +526 -0
- package/dist/lib/database-service/postgres-adapter.js.map +1 -0
- package/dist/lib/database-service/redis-adapter.js +360 -0
- package/dist/lib/database-service/redis-adapter.js.map +1 -0
- package/dist/lib/database-service/sqlite-adapter.js +544 -0
- package/dist/lib/database-service/sqlite-adapter.js.map +1 -0
- package/dist/lib/database-service/transaction-manager.js +773 -0
- package/dist/lib/database-service/transaction-manager.js.map +1 -0
- package/dist/lib/database-service/types.js +23 -0
- package/dist/lib/database-service/types.js.map +1 -0
- package/dist/lib/deadlock-resolver.js +292 -0
- package/dist/lib/deadlock-resolver.js.map +1 -0
- package/dist/lib/distributed-lock.js +451 -0
- package/dist/lib/distributed-lock.js.map +1 -0
- package/dist/lib/edge-case-deduplicator.js +227 -0
- package/dist/lib/edge-case-deduplicator.js.map +1 -0
- package/dist/lib/encryption-manager.js +322 -0
- package/dist/lib/encryption-manager.js.map +1 -0
- package/dist/lib/error-aggregator.js +234 -0
- package/dist/lib/error-aggregator.js.map +1 -0
- package/dist/lib/errors.js +287 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-lock-manager.js +578 -0
- package/dist/lib/file-lock-manager.js.map +1 -0
- package/dist/lib/file-operations.js +367 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/idempotent-write.js +237 -0
- package/dist/lib/idempotent-write.js.map +1 -0
- package/dist/lib/integration-schema-validator.js +522 -0
- package/dist/lib/integration-schema-validator.js.map +1 -0
- package/dist/lib/lock-health-monitor.js +298 -0
- package/dist/lib/lock-health-monitor.js.map +1 -0
- package/dist/lib/log-shipper.js +422 -0
- package/dist/lib/log-shipper.js.map +1 -0
- package/dist/lib/logging.js +146 -0
- package/dist/lib/logging.js.map +1 -0
- package/dist/lib/message-deduplicator.js +439 -0
- package/dist/lib/message-deduplicator.js.map +1 -0
- package/dist/lib/multi-system-query.js +604 -0
- package/dist/lib/multi-system-query.js.map +1 -0
- package/dist/lib/orphan-detector.js +332 -0
- package/dist/lib/orphan-detector.js.map +1 -0
- package/dist/lib/password-generator.js +166 -0
- package/dist/lib/password-generator.js.map +1 -0
- package/dist/lib/path-validator.js +429 -0
- package/dist/lib/path-validator.js.map +1 -0
- package/dist/lib/query-translator.js +905 -0
- package/dist/lib/query-translator.js.map +1 -0
- package/dist/lib/queue-recovery.js +469 -0
- package/dist/lib/queue-recovery.js.map +1 -0
- package/dist/lib/redis-queue-manager.js +512 -0
- package/dist/lib/redis-queue-manager.js.map +1 -0
- package/dist/lib/reflection-archiver.js +272 -0
- package/dist/lib/reflection-archiver.js.map +1 -0
- package/dist/lib/retry-manager.js +453 -0
- package/dist/lib/retry-manager.js.map +1 -0
- package/dist/lib/retry.js +262 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/schema-transform.js +695 -0
- package/dist/lib/schema-transform.js.map +1 -0
- package/dist/lib/schema-validator.js +491 -0
- package/dist/lib/schema-validator.js.map +1 -0
- package/dist/lib/skill-cache.js +297 -0
- package/dist/lib/skill-cache.js.map +1 -0
- package/dist/lib/skill-content-manager.js +337 -0
- package/dist/lib/skill-content-manager.js.map +1 -0
- package/dist/lib/skill-frontmatter-parser.js +237 -0
- package/dist/lib/skill-frontmatter-parser.js.map +1 -0
- package/dist/lib/skill-git-integration.js +275 -0
- package/dist/lib/skill-git-integration.js.map +1 -0
- package/dist/lib/skill-markdown-validator.js +396 -0
- package/dist/lib/skill-markdown-validator.js.map +1 -0
- package/dist/lib/skill-output-parser.js +312 -0
- package/dist/lib/skill-output-parser.js.map +1 -0
- package/dist/lib/unified-query-api.js +467 -0
- package/dist/lib/unified-query-api.js.map +1 -0
- package/dist/middleware/auth-middleware.js +350 -0
- package/dist/middleware/auth-middleware.js.map +1 -0
- package/dist/middleware/schema-validation.js +347 -0
- package/dist/middleware/schema-validation.js.map +1 -0
- package/dist/providers/anthropic-provider.js +1 -1
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/provider-factory.js +2 -2
- package/dist/providers/provider-factory.js.map +1 -1
- package/dist/services/edge-case-analyzer.js +321 -0
- package/dist/services/edge-case-analyzer.js.map +1 -0
- package/dist/services/edge-case-deduplicator.js +266 -0
- package/dist/services/edge-case-deduplicator.js.map +1 -0
- package/dist/services/edge-case-detector.js +337 -0
- package/dist/services/edge-case-detector.js.map +1 -0
- package/dist/services/edge-case-tracker.js +547 -0
- package/dist/services/edge-case-tracker.js.map +1 -0
- package/dist/services/health-check-system.js +586 -0
- package/dist/services/health-check-system.js.map +1 -0
- package/dist/services/metrics-logger.js +412 -0
- package/dist/services/metrics-logger.js.map +1 -0
- package/dist/services/patch-generator.js +378 -0
- package/dist/services/patch-generator.js.map +1 -0
- package/dist/services/patch-validator.js +337 -0
- package/dist/services/patch-validator.js.map +1 -0
- package/dist/services/performance-monitor.js +811 -0
- package/dist/services/performance-monitor.js.map +1 -0
- package/dist/services/promotion-pipeline.js +918 -0
- package/dist/services/promotion-pipeline.js.map +1 -0
- package/dist/services/promotion-validator.js +394 -0
- package/dist/services/promotion-validator.js.map +1 -0
- package/dist/services/reflection-logger.js +388 -0
- package/dist/services/reflection-logger.js.map +1 -0
- package/dist/services/skill-deployment.js +472 -0
- package/dist/services/skill-deployment.js.map +1 -0
- package/dist/services/skill-loader.js +427 -0
- package/dist/services/skill-loader.js.map +1 -0
- package/dist/services/skill-promotion.js +372 -0
- package/dist/services/skill-promotion.js.map +1 -0
- package/dist/services/skill-validator.js +454 -0
- package/dist/services/skill-validator.js.map +1 -0
- package/dist/services/skill-versioning.js +244 -0
- package/dist/services/skill-versioning.js.map +1 -0
- package/dist/services/workspace-supervisor.js +597 -0
- package/dist/services/workspace-supervisor.js.map +1 -0
- package/dist/types/edge-case.js +45 -0
- package/dist/types/edge-case.js.map +1 -0
- package/docs/BUG_19_MEMORY_LEAK_TASK_MODE.md +405 -0
- package/docs/MEMORY_CLEANUP_GUIDE.md +358 -0
- package/docs/MEMORY_LEAK_FIX_SUMMARY.md +322 -0
- package/docs/REDIS_CLEANUP_EXECUTIVE_SUMMARY.md +319 -0
- package/docs/REDIS_CLEANUP_VERIFICATION_REPORT.md +574 -0
- package/package.json +35 -4
- package/readme/README.md +53 -5
- package/scripts/backup-cleanup.sh +627 -0
- package/scripts/cleanup-workspaces.sh +412 -0
- package/scripts/cleanup-yaml-configs.sh +141 -0
- package/scripts/deploy-approved-skills.sh +263 -0
- package/scripts/health-check.sh +447 -0
- package/scripts/log-aggregator.sh +554 -0
- package/scripts/log-monitor.sh +629 -0
- package/scripts/manage-agent-workspaces.sh +434 -0
- package/scripts/migrate-schema.sh +533 -0
- package/scripts/promote-staged-skills.sh +423 -0
- package/scripts/verify-no-secrets.sh +88 -35
- package/scripts/verify-redis-cleanup.sh +173 -0
- package/tests/README.md +84 -0
- package/tests/test-memory-leak-task-mode.sh +435 -0
- package/.claude/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/.claude/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/.claude/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/.claude/skills/agent-lifecycle/SKILL.md +0 -60
- package/.claude/skills/agent-lifecycle/execute-lifecycle-hook.sh +0 -573
- package/.claude/skills/agent-lifecycle/simple-audit.sh +0 -31
- package/.claude/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
- package/README.md.backup_before_replace +0 -781
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/adaptive-coordinator.md.backup +0 -161
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/blocking-coordinator-example.md.backup +0 -728
- package/claude-assets/cfn-extras/agents/deprecated-coordinators/mesh-coordinator.md.backup +0 -131
- package/claude-assets/skills/cfn-agent-spawning/spawn-agent.sh.backup +0 -273
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh.backup +0 -949
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/password-generator.ts"],"sourcesContent":["/**\r\n * Secure Password Generator\r\n *\r\n * Generates cryptographically secure passwords for database authentication\r\n * with configurable complexity requirements and validation.\r\n *\r\n * Security Standards:\r\n * - Uses crypto.randomBytes() for cryptographic randomness\r\n * - Default minimum 32 characters for high entropy\r\n * - Requires mixed character types (uppercase, lowercase, digits, special)\r\n * - No ambiguous characters (0/O, 1/l, etc.)\r\n * - Suitable for Redis requirepass and PostgreSQL authentication\r\n */\r\n\r\nimport { randomBytes } from 'crypto';\r\n\r\nexport interface PasswordOptions {\r\n length?: number;\r\n uppercase?: boolean;\r\n lowercase?: boolean;\r\n digits?: boolean;\r\n special?: boolean;\r\n excludeAmbiguous?: boolean;\r\n}\r\n\r\nexport interface PasswordValidationResult {\r\n valid: boolean;\r\n length: number;\r\n hasUppercase: boolean;\r\n hasLowercase: boolean;\r\n hasDigits: boolean;\r\n hasSpecial: boolean;\r\n errors: string[];\r\n}\r\n\r\n/**\r\n * Default character sets for password generation\r\n */\r\nconst CHAR_SETS = {\r\n uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',\r\n uppercaseNoAmbiguous: 'ABCDEFGHJKMNPQRSTUVWXYZ', // Removed: I, L, O\r\n lowercase: 'abcdefghijklmnopqrstuvwxyz',\r\n lowercaseNoAmbiguous: 'abcdefghjkmnpqrstuvwxyz', // Removed: i, l, o\r\n digits: '0123456789',\r\n digitsNoAmbiguous: '23456789', // Removed: 0, 1\r\n special: '!@#$%^&*()_+-=[]{}|;:,.<>?',\r\n specialSafe: '!@#%^&*_+-=', // Removed: $, `, \", ' for environment variable safety\r\n};\r\n\r\n/**\r\n * Generate a cryptographically secure random password\r\n */\r\nexport function generatePassword(options: PasswordOptions = {}): string {\r\n const {\r\n length = 32,\r\n uppercase = true,\r\n lowercase = true,\r\n digits = true,\r\n special = true,\r\n excludeAmbiguous = true,\r\n } = options;\r\n\r\n if (length < 16) {\r\n throw new Error('Password length must be at least 16 characters');\r\n }\r\n\r\n // Build character pool\r\n let charPool = '';\r\n const selectedSets: string[] = [];\r\n\r\n if (uppercase) {\r\n const chars = excludeAmbiguous ? CHAR_SETS.uppercaseNoAmbiguous : CHAR_SETS.uppercase;\r\n charPool += chars;\r\n selectedSets.push('uppercase');\r\n }\r\n\r\n if (lowercase) {\r\n const chars = excludeAmbiguous ? CHAR_SETS.lowercaseNoAmbiguous : CHAR_SETS.lowercase;\r\n charPool += chars;\r\n selectedSets.push('lowercase');\r\n }\r\n\r\n if (digits) {\r\n const chars = excludeAmbiguous ? CHAR_SETS.digitsNoAmbiguous : CHAR_SETS.digits;\r\n charPool += chars;\r\n selectedSets.push('digits');\r\n }\r\n\r\n if (special) {\r\n charPool += CHAR_SETS.specialSafe;\r\n selectedSets.push('special');\r\n }\r\n\r\n if (charPool.length === 0) {\r\n throw new Error('At least one character type must be enabled');\r\n }\r\n\r\n // Ensure password contains at least one character from each required type\r\n const password = new Array(length);\r\n let generated = 0;\r\n\r\n // First, place one character from each required set\r\n for (const setName of selectedSets) {\r\n let setChars: string;\r\n switch (setName) {\r\n case 'uppercase':\r\n setChars = uppercase ? (excludeAmbiguous ? CHAR_SETS.uppercaseNoAmbiguous : CHAR_SETS.uppercase) : '';\r\n break;\r\n case 'lowercase':\r\n setChars = lowercase ? (excludeAmbiguous ? CHAR_SETS.lowercaseNoAmbiguous : CHAR_SETS.lowercase) : '';\r\n break;\r\n case 'digits':\r\n setChars = digits ? (excludeAmbiguous ? CHAR_SETS.digitsNoAmbiguous : CHAR_SETS.digits) : '';\r\n break;\r\n case 'special':\r\n setChars = special ? CHAR_SETS.specialSafe : '';\r\n break;\r\n default:\r\n setChars = '';\r\n }\r\n\r\n if (setChars.length > 0 && generated < length) {\r\n const index = cryptoRandom(0, setChars.length - 1);\r\n password[generated] = setChars[index];\r\n generated++;\r\n }\r\n }\r\n\r\n // Fill remaining positions with random characters from pool\r\n while (generated < length) {\r\n const index = cryptoRandom(0, charPool.length - 1);\r\n password[generated] = charPool[index];\r\n generated++;\r\n }\r\n\r\n // Shuffle password to avoid predictable patterns\r\n return shuffleArray(password).join('');\r\n}\r\n\r\n/**\r\n * Validate password meets security requirements\r\n */\r\nexport function validatePassword(password: string, minLength: number = 32): PasswordValidationResult {\r\n const errors: string[] = [];\r\n const hasUppercase = /[A-Z]/.test(password);\r\n const hasLowercase = /[a-z]/.test(password);\r\n const hasDigits = /\\d/.test(password);\r\n const hasSpecial = /[!@#$%^&*()_+\\-=\\[\\]{}|;:,.<>?]/.test(password);\r\n\r\n if (password.length < minLength) {\r\n errors.push(`Password must be at least ${minLength} characters long (current: ${password.length})`);\r\n }\r\n\r\n if (!hasUppercase) {\r\n errors.push('Password must contain at least one uppercase letter');\r\n }\r\n\r\n if (!hasLowercase) {\r\n errors.push('Password must contain at least one lowercase letter');\r\n }\r\n\r\n if (!hasDigits) {\r\n errors.push('Password must contain at least one digit');\r\n }\r\n\r\n if (!hasSpecial) {\r\n errors.push('Password must contain at least one special character');\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n length: password.length,\r\n hasUppercase,\r\n hasLowercase,\r\n hasDigits,\r\n hasSpecial,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Generate a cryptographically secure random integer in range [min, max]\r\n */\r\nfunction cryptoRandom(min: number, max: number): number {\r\n if (min < 0 || max < 0 || min > max) {\r\n throw new Error('Invalid range: min must be >= 0 and min must be <= max');\r\n }\r\n\r\n const range = max - min + 1;\r\n const bytesNeeded = Math.ceil(Math.log2(range) / 8);\r\n const randomBytes_ = randomBytes(bytesNeeded);\r\n\r\n // Convert bytes to integer and apply modulo to ensure uniform distribution\r\n let randomValue = 0;\r\n for (let i = 0; i < bytesNeeded; i++) {\r\n randomValue = (randomValue << 8) | randomBytes_[i];\r\n }\r\n\r\n // Use rejection sampling to ensure uniform distribution\r\n const limit = Math.floor(256 ** bytesNeeded / range) * range;\r\n\r\n if (randomValue < limit) {\r\n return min + (randomValue % range);\r\n }\r\n\r\n // Recursively try again if we exceeded the limit (very rare)\r\n return cryptoRandom(min, max);\r\n}\r\n\r\n/**\r\n * Shuffle array in-place using Fisher-Yates algorithm\r\n */\r\nfunction shuffleArray<T>(array: T[]): T[] {\r\n const shuffled = [...array];\r\n\r\n for (let i = shuffled.length - 1; i > 0; i--) {\r\n const j = cryptoRandom(0, i);\r\n [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];\r\n }\r\n\r\n return shuffled;\r\n}\r\n"],"names":["randomBytes","CHAR_SETS","uppercase","uppercaseNoAmbiguous","lowercase","lowercaseNoAmbiguous","digits","digitsNoAmbiguous","special","specialSafe","generatePassword","options","length","excludeAmbiguous","Error","charPool","selectedSets","chars","push","password","Array","generated","setName","setChars","index","cryptoRandom","shuffleArray","join","validatePassword","minLength","errors","hasUppercase","test","hasLowercase","hasDigits","hasSpecial","valid","min","max","range","bytesNeeded","Math","ceil","log2","randomBytes_","randomValue","i","limit","floor","array","shuffled","j"],"mappings":"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"}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Validator - Security Utility for Safe File Operations
|
|
3
|
+
*
|
|
4
|
+
* Provides robust path sanitization and validation to prevent path traversal attacks (CVSS 7.0+).
|
|
5
|
+
* Enforces strict rules on file access with protection against encoding attacks:
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL FIXES (CVSS 7.0+):
|
|
8
|
+
* - Iterative URL decoding prevents double-encoding bypasses (%252e%252e%252f → ../)
|
|
9
|
+
* - Unicode normalization (NFC) prevents overlong UTF-8 bypasses (%c0%ae → .)
|
|
10
|
+
* - Null byte detection prevents null injection attacks
|
|
11
|
+
* - All decoding performed BEFORE path normalization to prevent layered attacks
|
|
12
|
+
* - Encoding attack detection with security logging
|
|
13
|
+
*
|
|
14
|
+
* Base Security Controls:
|
|
15
|
+
* - Path normalization to resolve ".." and "." sequences
|
|
16
|
+
* - Validation that resolved paths stay within allowed directories
|
|
17
|
+
* - Detection and rejection of symlinks
|
|
18
|
+
* - Rejection of absolute paths outside allowed directories
|
|
19
|
+
* - Prevention of home directory access ("~")
|
|
20
|
+
*
|
|
21
|
+
* @module path-validator
|
|
22
|
+
* @version 2.0.0 (SECURITY CRITICAL)
|
|
23
|
+
*/ import * as path from 'path';
|
|
24
|
+
import * as fs from 'fs';
|
|
25
|
+
import { StandardError } from './errors';
|
|
26
|
+
/**
|
|
27
|
+
* Path validation error - thrown when a path violates security constraints
|
|
28
|
+
*/ export class PathValidationError extends StandardError {
|
|
29
|
+
constructor(message, context){
|
|
30
|
+
super('PATH_VALIDATION_ERROR', message, context);
|
|
31
|
+
this.name = 'PathValidationError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Safely decode a path with protection against encoding attacks
|
|
36
|
+
*
|
|
37
|
+
* Performs iterative URL decoding and Unicode normalization to prevent:
|
|
38
|
+
* - Double encoding bypass (e.g., %252e%252e%252f → %2e%2e%2f → ../)
|
|
39
|
+
* - Overlong UTF-8 encoding (e.g., %c0%ae%c0%ae/ → ../)
|
|
40
|
+
* - Mixed encoding attacks
|
|
41
|
+
*
|
|
42
|
+
* @param inputPath - The potentially encoded path
|
|
43
|
+
* @returns Decoded path and attack detection info
|
|
44
|
+
* @throws PathValidationError if encoding attack detected
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const { decoded, encoding } = decodePathSafely('%252e%252e%252f');
|
|
48
|
+
* // Detects double-encoding attempt
|
|
49
|
+
*/ function decodePathSafely(inputPath) {
|
|
50
|
+
let decoded = inputPath;
|
|
51
|
+
let previous = '';
|
|
52
|
+
let iterations = 0;
|
|
53
|
+
const MAX_ITERATIONS = 5;
|
|
54
|
+
const originalInput = inputPath;
|
|
55
|
+
let invalidEncodingDetected = false;
|
|
56
|
+
// Iteratively decode URL-encoded characters until stable
|
|
57
|
+
// This prevents bypass attacks using multiple encoding layers
|
|
58
|
+
while(decoded !== previous && iterations < MAX_ITERATIONS){
|
|
59
|
+
previous = decoded;
|
|
60
|
+
try {
|
|
61
|
+
decoded = decodeURIComponent(decoded);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Invalid URL encoding (including malformed UTF-8) indicates attack
|
|
64
|
+
// e.g., %c0%ae is malformed UTF-8 for overlong encoding
|
|
65
|
+
invalidEncodingDetected = true;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
iterations++;
|
|
69
|
+
}
|
|
70
|
+
// Check if we hit max iterations (indicates potential encoding attack)
|
|
71
|
+
if (iterations >= MAX_ITERATIONS && decoded !== previous) {
|
|
72
|
+
throw new PathValidationError('Path validation failed: excessive encoding layers detected', {
|
|
73
|
+
originalInput,
|
|
74
|
+
decodedOutput: decoded,
|
|
75
|
+
iterations,
|
|
76
|
+
reason: 'ENCODING_ATTACK_DETECTED'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Invalid encoding like malformed UTF-8 is itself an attack indicator
|
|
80
|
+
if (invalidEncodingDetected) {
|
|
81
|
+
throw new PathValidationError('Path validation failed: invalid encoding detected (possible encoding attack)', {
|
|
82
|
+
originalInput,
|
|
83
|
+
decodedOutput: decoded,
|
|
84
|
+
iterations,
|
|
85
|
+
reason: 'INVALID_ENCODING_DETECTED'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Detect if decoding required multiple iterations (possible double-encoding attack)
|
|
89
|
+
const encodingAttackDetected = iterations > 1;
|
|
90
|
+
// Unicode normalization to handle overlong UTF-8 sequences
|
|
91
|
+
// e.g., %c0%ae (%c0%ae = UTF-8 overlong encoding for ".")
|
|
92
|
+
let normalized = decoded;
|
|
93
|
+
try {
|
|
94
|
+
normalized = decoded.normalize('NFC');
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// Some paths may not be valid Unicode, continue with non-normalized version
|
|
97
|
+
}
|
|
98
|
+
// Check for null bytes (another common encoding attack vector)
|
|
99
|
+
if (normalized.includes('\0')) {
|
|
100
|
+
throw new PathValidationError('Path validation failed: null byte injection detected', {
|
|
101
|
+
originalInput,
|
|
102
|
+
decodedOutput: normalized,
|
|
103
|
+
reason: 'NULL_BYTE_INJECTION'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
decoded: normalized,
|
|
108
|
+
encoding: {
|
|
109
|
+
detected: encodingAttackDetected,
|
|
110
|
+
type: encodingAttackDetected ? 'double_encoding' : undefined,
|
|
111
|
+
originalInput,
|
|
112
|
+
decodedOutput: normalized,
|
|
113
|
+
iterationsRequired: iterations
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Validate a file path to prevent directory traversal attacks
|
|
119
|
+
*
|
|
120
|
+
* Security checks performed (in order):
|
|
121
|
+
* 1. CRITICAL: Iteratively decode URL encoding to handle %252e%252e%252f and similar bypasses
|
|
122
|
+
* 2. CRITICAL: Normalize Unicode (NFC) to handle overlong UTF-8 like %c0%ae%c0%ae/
|
|
123
|
+
* 3. CRITICAL: Detect null bytes and excessive encoding layers
|
|
124
|
+
* 4. Check for home directory expansion ("~") on DECODED path
|
|
125
|
+
* 5. Normalize path to resolve ".." and "."
|
|
126
|
+
* 6. Verify all suspicious patterns are eliminated
|
|
127
|
+
* 7. Check if path is within base directory
|
|
128
|
+
* 8. Reject symlinks to prevent symlink attacks
|
|
129
|
+
* 9. Log any encoding attacks detected for security monitoring
|
|
130
|
+
*
|
|
131
|
+
* @param filePath - The file path to validate (may be encoded)
|
|
132
|
+
* @param baseDirectory - The base directory that file must reside within
|
|
133
|
+
* @returns PathValidationResult with validation details
|
|
134
|
+
* @throws PathValidationError if path validation fails or encoding attack detected
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const result = validatePath('docs/FEATURE.md', './.claude/skills');
|
|
138
|
+
* if (!result.valid) {
|
|
139
|
+
* throw result; // Safe to throw, contains all context
|
|
140
|
+
* }
|
|
141
|
+
* // Use result.resolvedPath
|
|
142
|
+
*
|
|
143
|
+
* @security
|
|
144
|
+
* Designed to prevent:
|
|
145
|
+
* - Double-encoding bypasses: %252e%252e%252f
|
|
146
|
+
* - Overlong UTF-8: %c0%ae%c0%ae/
|
|
147
|
+
* - Mixed encoding: URL + Unicode combinations
|
|
148
|
+
* - Null byte injection: file.txt%00.jpg
|
|
149
|
+
* - Traditional path traversal: ../../../etc/passwd
|
|
150
|
+
*/ export function validatePath(filePath, baseDirectory) {
|
|
151
|
+
// SECURITY FIX: Decode all encoding layers first before any path normalization
|
|
152
|
+
// This prevents double-encoding bypasses like %252e%252e%252f
|
|
153
|
+
const { decoded: decodedPath, encoding: pathEncoding } = decodePathSafely(filePath);
|
|
154
|
+
const { decoded: decodedBase } = decodePathSafely(baseDirectory);
|
|
155
|
+
// Log encoding attacks for security monitoring
|
|
156
|
+
if (pathEncoding.detected) {
|
|
157
|
+
// In production, this should trigger security alerts
|
|
158
|
+
console.warn('Security: Encoding attack detected in path input', {
|
|
159
|
+
originalInput: pathEncoding.originalInput,
|
|
160
|
+
decodedOutput: pathEncoding.decodedOutput,
|
|
161
|
+
iterationsRequired: pathEncoding.iterationsRequired
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// Check for home directory expansion attempts on DECODED path
|
|
165
|
+
if (decodedPath.startsWith('~') || decodedPath.includes('/~') || decodedPath.includes('\\~')) {
|
|
166
|
+
throw new PathValidationError('Path validation failed: home directory access denied', {
|
|
167
|
+
filePath,
|
|
168
|
+
decodedPath,
|
|
169
|
+
baseDirectory,
|
|
170
|
+
reason: 'HOME_DIRECTORY_ACCESS'
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Check for home directory expansion attempts in baseDirectory
|
|
174
|
+
if (decodedBase.startsWith('~')) {
|
|
175
|
+
throw new PathValidationError('Base directory validation failed: home directory access denied', {
|
|
176
|
+
baseDirectory,
|
|
177
|
+
decodedBase,
|
|
178
|
+
reason: 'BASE_HOME_DIRECTORY_ACCESS'
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Normalize the base directory first
|
|
182
|
+
const normalizedBase = path.normalize(decodedBase);
|
|
183
|
+
const resolvedBase = path.resolve(normalizedBase);
|
|
184
|
+
// Normalize and resolve the file path relative to base
|
|
185
|
+
// NOW normalized on already-decoded path to prevent encoding bypasses
|
|
186
|
+
const normalizedPath = path.normalize(decodedPath);
|
|
187
|
+
// Check if path contains suspicious patterns after normalization
|
|
188
|
+
if (normalizedPath.includes('..') || normalizedPath === '.' || normalizedPath.includes('/./')) {
|
|
189
|
+
throw new PathValidationError('Path validation failed: path contains directory traversal patterns', {
|
|
190
|
+
filePath,
|
|
191
|
+
decodedPath,
|
|
192
|
+
normalizedPath,
|
|
193
|
+
baseDirectory,
|
|
194
|
+
reason: 'TRAVERSAL_PATTERN_DETECTED'
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Resolve the path relative to base directory
|
|
198
|
+
const resolvedPath = path.resolve(resolvedBase, normalizedPath);
|
|
199
|
+
// Check if resolved path is within base directory
|
|
200
|
+
const isWithinBase = isPathWithinBase(resolvedPath, resolvedBase);
|
|
201
|
+
if (!isWithinBase) {
|
|
202
|
+
throw new PathValidationError('Path validation failed: resolved path is outside allowed directory', {
|
|
203
|
+
filePath,
|
|
204
|
+
resolvedPath,
|
|
205
|
+
baseDirectory: resolvedBase,
|
|
206
|
+
reason: 'PATH_OUTSIDE_BASE'
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Check for symlinks (prevents symlink attacks)
|
|
210
|
+
let isSymlink = false;
|
|
211
|
+
try {
|
|
212
|
+
const stats = fs.lstatSync(resolvedPath);
|
|
213
|
+
isSymlink = stats.isSymbolicLink();
|
|
214
|
+
if (isSymlink) {
|
|
215
|
+
throw new PathValidationError('Path validation failed: symbolic links are not allowed', {
|
|
216
|
+
filePath,
|
|
217
|
+
resolvedPath,
|
|
218
|
+
reason: 'SYMLINK_NOT_ALLOWED'
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
// File doesn't exist yet (expected for validation before creation)
|
|
223
|
+
// or it's a symlink that was rejected above
|
|
224
|
+
if (error instanceof PathValidationError) {
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
// Other errors (permission denied, etc.) are not path validation failures
|
|
228
|
+
// The file validation happens later
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
valid: true,
|
|
232
|
+
resolvedPath,
|
|
233
|
+
normalizedPath,
|
|
234
|
+
isWithinBase: true,
|
|
235
|
+
isSymlink: false
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Check if a path is within a base directory
|
|
240
|
+
*
|
|
241
|
+
* Uses path resolution and string comparison to ensure the resolved path
|
|
242
|
+
* is actually within the base directory (not just sharing a prefix).
|
|
243
|
+
*
|
|
244
|
+
* @param filePath - The path to check
|
|
245
|
+
* @param baseDirectory - The base directory
|
|
246
|
+
* @returns True if filePath is within baseDirectory
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* isPathWithinBase('/home/user/project/src/file.ts', '/home/user/project') // true
|
|
250
|
+
* isPathWithinBase('/home/user/project-evil/file.ts', '/home/user/project') // false
|
|
251
|
+
*/ export function isPathWithinBase(filePath, baseDirectory) {
|
|
252
|
+
// Ensure both paths are normalized and absolute
|
|
253
|
+
const normalizedFile = path.normalize(path.resolve(filePath));
|
|
254
|
+
const normalizedBase = path.normalize(path.resolve(baseDirectory));
|
|
255
|
+
// Exact match
|
|
256
|
+
if (normalizedFile === normalizedBase) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
// Check if file is within base (use path.relative to ensure it's not going up)
|
|
260
|
+
const relative = path.relative(normalizedBase, normalizedFile);
|
|
261
|
+
// If relative path starts with "..", it's outside the base directory
|
|
262
|
+
if (relative.startsWith('..')) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
// If relative path is absolute, it's outside the base directory
|
|
266
|
+
if (path.isAbsolute(relative)) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Validate multiple paths within the same base directory
|
|
273
|
+
*
|
|
274
|
+
* Efficiently validates multiple paths, returning results for each.
|
|
275
|
+
*
|
|
276
|
+
* @param filePaths - Array of file paths to validate
|
|
277
|
+
* @param baseDirectory - The base directory that all files must reside within
|
|
278
|
+
* @returns Map of file path to validation result
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* const results = validatePaths(['docs/SKILL.md', 'src/index.ts'], './.claude/skills');
|
|
282
|
+
* results.forEach((result, filePath) => {
|
|
283
|
+
* if (!result.valid) {
|
|
284
|
+
* console.error(`Invalid path: ${filePath}`, result.reason);
|
|
285
|
+
* }
|
|
286
|
+
* });
|
|
287
|
+
*/ export function validatePaths(filePaths, baseDirectory) {
|
|
288
|
+
const results = new Map();
|
|
289
|
+
for (const filePath of filePaths){
|
|
290
|
+
try {
|
|
291
|
+
const result = validatePath(filePath, baseDirectory);
|
|
292
|
+
results.set(filePath, result);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if (error instanceof PathValidationError) {
|
|
295
|
+
results.set(filePath, {
|
|
296
|
+
valid: false,
|
|
297
|
+
resolvedPath: '',
|
|
298
|
+
normalizedPath: '',
|
|
299
|
+
isWithinBase: false,
|
|
300
|
+
isSymlink: false,
|
|
301
|
+
reason: error.context?.reason
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return results;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get the safe path for a file (or throw if validation fails)
|
|
312
|
+
*
|
|
313
|
+
* Convenience function that validates and returns the resolved path,
|
|
314
|
+
* or throws an error if validation fails.
|
|
315
|
+
*
|
|
316
|
+
* @param filePath - The file path to validate
|
|
317
|
+
* @param baseDirectory - The base directory that file must reside within
|
|
318
|
+
* @returns The resolved, validated absolute path
|
|
319
|
+
* @throws PathValidationError if path validation fails
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* const safePath = getSafePath('docs/SKILL.md', './.claude/skills');
|
|
323
|
+
* fs.readFileSync(safePath); // Safe to use
|
|
324
|
+
*/ export function getSafePath(filePath, baseDirectory) {
|
|
325
|
+
const result = validatePath(filePath, baseDirectory);
|
|
326
|
+
return result.resolvedPath;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Check if a path is considered safe for operations
|
|
330
|
+
*
|
|
331
|
+
* This is a non-throwing version of validatePath for conditional logic.
|
|
332
|
+
*
|
|
333
|
+
* @param filePath - The file path to check
|
|
334
|
+
* @param baseDirectory - The base directory
|
|
335
|
+
* @returns True if path is safe, false otherwise
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* if (isPathSafe(userInput, './.claude/skills')) {
|
|
339
|
+
* // Process the file
|
|
340
|
+
* } else {
|
|
341
|
+
* // Reject the request
|
|
342
|
+
* }
|
|
343
|
+
*/ export function isPathSafe(filePath, baseDirectory) {
|
|
344
|
+
try {
|
|
345
|
+
validatePath(filePath, baseDirectory);
|
|
346
|
+
return true;
|
|
347
|
+
} catch {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get validation error details for a path (if invalid)
|
|
353
|
+
*
|
|
354
|
+
* Useful for logging and diagnostics.
|
|
355
|
+
*
|
|
356
|
+
* @param filePath - The file path to validate
|
|
357
|
+
* @param baseDirectory - The base directory
|
|
358
|
+
* @returns Error with details, or undefined if path is valid
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* const error = getPathValidationError('../../etc/passwd', './.claude/skills');
|
|
362
|
+
* if (error) {
|
|
363
|
+
* logger.error(error.message, error.context);
|
|
364
|
+
* }
|
|
365
|
+
*/ export function getPathValidationError(filePath, baseDirectory) {
|
|
366
|
+
try {
|
|
367
|
+
validatePath(filePath, baseDirectory);
|
|
368
|
+
return undefined;
|
|
369
|
+
} catch (error) {
|
|
370
|
+
if (error instanceof PathValidationError) {
|
|
371
|
+
return error;
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* List allowed files within a base directory (safely)
|
|
378
|
+
*
|
|
379
|
+
* Recursively lists all files within base directory, validating
|
|
380
|
+
* each path to ensure it's within bounds.
|
|
381
|
+
*
|
|
382
|
+
* @param baseDirectory - The base directory to scan
|
|
383
|
+
* @param options - Options for listing (maxDepth, filter)
|
|
384
|
+
* @returns Array of validated, safe paths relative to baseDirectory
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* const files = safeListDirectory('./.claude/skills');
|
|
388
|
+
* files.forEach(file => {
|
|
389
|
+
* // All paths are guaranteed safe
|
|
390
|
+
* console.log(file);
|
|
391
|
+
* });
|
|
392
|
+
*/ export function safeListDirectory(baseDirectory, options) {
|
|
393
|
+
const safeFiles = [];
|
|
394
|
+
const maxDepth = options?.maxDepth ?? Infinity;
|
|
395
|
+
const filter = options?.filter ?? (()=>true);
|
|
396
|
+
function walkDirectory(dir, currentDepth = 0) {
|
|
397
|
+
if (currentDepth > maxDepth) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
const entries = fs.readdirSync(dir, {
|
|
402
|
+
withFileTypes: true
|
|
403
|
+
});
|
|
404
|
+
for (const entry of entries){
|
|
405
|
+
const fullPath = path.join(dir, entry.name);
|
|
406
|
+
const relativePath = path.relative(baseDirectory, fullPath);
|
|
407
|
+
// Validate the path is still within base
|
|
408
|
+
if (!isPathWithinBase(fullPath, baseDirectory)) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
// Apply filter
|
|
412
|
+
if (!filter(relativePath)) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
safeFiles.push(relativePath);
|
|
416
|
+
// Recursively walk directories
|
|
417
|
+
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
418
|
+
walkDirectory(fullPath, currentDepth + 1);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch (error) {
|
|
422
|
+
// Silently skip directories we can't read (permission denied, etc.)
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
walkDirectory(baseDirectory);
|
|
426
|
+
return safeFiles;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
//# sourceMappingURL=path-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/path-validator.ts"],"sourcesContent":["/**\r\n * Path Validator - Security Utility for Safe File Operations\r\n *\r\n * Provides robust path sanitization and validation to prevent path traversal attacks (CVSS 7.0+).\r\n * Enforces strict rules on file access with protection against encoding attacks:\r\n *\r\n * CRITICAL FIXES (CVSS 7.0+):\r\n * - Iterative URL decoding prevents double-encoding bypasses (%252e%252e%252f → ../)\r\n * - Unicode normalization (NFC) prevents overlong UTF-8 bypasses (%c0%ae → .)\r\n * - Null byte detection prevents null injection attacks\r\n * - All decoding performed BEFORE path normalization to prevent layered attacks\r\n * - Encoding attack detection with security logging\r\n *\r\n * Base Security Controls:\r\n * - Path normalization to resolve \"..\" and \".\" sequences\r\n * - Validation that resolved paths stay within allowed directories\r\n * - Detection and rejection of symlinks\r\n * - Rejection of absolute paths outside allowed directories\r\n * - Prevention of home directory access (\"~\")\r\n *\r\n * @module path-validator\r\n * @version 2.0.0 (SECURITY CRITICAL)\r\n */\r\n\r\nimport * as path from 'path';\r\nimport * as fs from 'fs';\r\nimport { StandardError } from './errors';\r\n\r\n/**\r\n * Path validation error - thrown when a path violates security constraints\r\n */\r\nexport class PathValidationError extends StandardError {\r\n constructor(message: string, context?: Record<string, unknown>) {\r\n super('PATH_VALIDATION_ERROR', message, context);\r\n this.name = 'PathValidationError';\r\n }\r\n}\r\n\r\n/**\r\n * Security encoding attack detection\r\n */\r\nexport interface EncodingAttackDetection {\r\n detected: boolean;\r\n type?: 'double_encoding' | 'unicode_encoding' | 'mixed_encoding';\r\n originalInput: string;\r\n decodedOutput: string;\r\n iterationsRequired: number;\r\n}\r\n\r\n/**\r\n * Path validation result with detailed information\r\n */\r\nexport interface PathValidationResult {\r\n valid: boolean;\r\n resolvedPath: string;\r\n normalizedPath: string;\r\n isWithinBase: boolean;\r\n isSymlink: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Safely decode a path with protection against encoding attacks\r\n *\r\n * Performs iterative URL decoding and Unicode normalization to prevent:\r\n * - Double encoding bypass (e.g., %252e%252e%252f → %2e%2e%2f → ../)\r\n * - Overlong UTF-8 encoding (e.g., %c0%ae%c0%ae/ → ../)\r\n * - Mixed encoding attacks\r\n *\r\n * @param inputPath - The potentially encoded path\r\n * @returns Decoded path and attack detection info\r\n * @throws PathValidationError if encoding attack detected\r\n *\r\n * @example\r\n * const { decoded, encoding } = decodePathSafely('%252e%252e%252f');\r\n * // Detects double-encoding attempt\r\n */\r\nfunction decodePathSafely(inputPath: string): {\r\n decoded: string;\r\n encoding: EncodingAttackDetection;\r\n} {\r\n let decoded = inputPath;\r\n let previous = '';\r\n let iterations = 0;\r\n const MAX_ITERATIONS = 5;\r\n const originalInput = inputPath;\r\n let invalidEncodingDetected = false;\r\n\r\n // Iteratively decode URL-encoded characters until stable\r\n // This prevents bypass attacks using multiple encoding layers\r\n while (decoded !== previous && iterations < MAX_ITERATIONS) {\r\n previous = decoded;\r\n try {\r\n decoded = decodeURIComponent(decoded);\r\n } catch (error) {\r\n // Invalid URL encoding (including malformed UTF-8) indicates attack\r\n // e.g., %c0%ae is malformed UTF-8 for overlong encoding\r\n invalidEncodingDetected = true;\r\n // Treat invalid encoding as a suspicious attack indicator\r\n // but continue with the path as-is for analysis\r\n break;\r\n }\r\n iterations++;\r\n }\r\n\r\n // Check if we hit max iterations (indicates potential encoding attack)\r\n if (iterations >= MAX_ITERATIONS && decoded !== previous) {\r\n throw new PathValidationError(\r\n 'Path validation failed: excessive encoding layers detected',\r\n {\r\n originalInput,\r\n decodedOutput: decoded,\r\n iterations,\r\n reason: 'ENCODING_ATTACK_DETECTED',\r\n }\r\n );\r\n }\r\n\r\n // Invalid encoding like malformed UTF-8 is itself an attack indicator\r\n if (invalidEncodingDetected) {\r\n throw new PathValidationError(\r\n 'Path validation failed: invalid encoding detected (possible encoding attack)',\r\n {\r\n originalInput,\r\n decodedOutput: decoded,\r\n iterations,\r\n reason: 'INVALID_ENCODING_DETECTED',\r\n }\r\n );\r\n }\r\n\r\n // Detect if decoding required multiple iterations (possible double-encoding attack)\r\n const encodingAttackDetected = iterations > 1;\r\n\r\n // Unicode normalization to handle overlong UTF-8 sequences\r\n // e.g., %c0%ae (%c0%ae = UTF-8 overlong encoding for \".\")\r\n let normalized = decoded;\r\n try {\r\n normalized = decoded.normalize('NFC');\r\n } catch (error) {\r\n // Some paths may not be valid Unicode, continue with non-normalized version\r\n }\r\n\r\n // Check for null bytes (another common encoding attack vector)\r\n if (normalized.includes('\\0')) {\r\n throw new PathValidationError(\r\n 'Path validation failed: null byte injection detected',\r\n {\r\n originalInput,\r\n decodedOutput: normalized,\r\n reason: 'NULL_BYTE_INJECTION',\r\n }\r\n );\r\n }\r\n\r\n return {\r\n decoded: normalized,\r\n encoding: {\r\n detected: encodingAttackDetected,\r\n type: encodingAttackDetected ? 'double_encoding' : undefined,\r\n originalInput,\r\n decodedOutput: normalized,\r\n iterationsRequired: iterations,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Validate a file path to prevent directory traversal attacks\r\n *\r\n * Security checks performed (in order):\r\n * 1. CRITICAL: Iteratively decode URL encoding to handle %252e%252e%252f and similar bypasses\r\n * 2. CRITICAL: Normalize Unicode (NFC) to handle overlong UTF-8 like %c0%ae%c0%ae/\r\n * 3. CRITICAL: Detect null bytes and excessive encoding layers\r\n * 4. Check for home directory expansion (\"~\") on DECODED path\r\n * 5. Normalize path to resolve \"..\" and \".\"\r\n * 6. Verify all suspicious patterns are eliminated\r\n * 7. Check if path is within base directory\r\n * 8. Reject symlinks to prevent symlink attacks\r\n * 9. Log any encoding attacks detected for security monitoring\r\n *\r\n * @param filePath - The file path to validate (may be encoded)\r\n * @param baseDirectory - The base directory that file must reside within\r\n * @returns PathValidationResult with validation details\r\n * @throws PathValidationError if path validation fails or encoding attack detected\r\n *\r\n * @example\r\n * const result = validatePath('docs/FEATURE.md', './.claude/skills');\r\n * if (!result.valid) {\r\n * throw result; // Safe to throw, contains all context\r\n * }\r\n * // Use result.resolvedPath\r\n *\r\n * @security\r\n * Designed to prevent:\r\n * - Double-encoding bypasses: %252e%252e%252f\r\n * - Overlong UTF-8: %c0%ae%c0%ae/\r\n * - Mixed encoding: URL + Unicode combinations\r\n * - Null byte injection: file.txt%00.jpg\r\n * - Traditional path traversal: ../../../etc/passwd\r\n */\r\nexport function validatePath(filePath: string, baseDirectory: string): PathValidationResult {\r\n // SECURITY FIX: Decode all encoding layers first before any path normalization\r\n // This prevents double-encoding bypasses like %252e%252e%252f\r\n const { decoded: decodedPath, encoding: pathEncoding } = decodePathSafely(filePath);\r\n const { decoded: decodedBase } = decodePathSafely(baseDirectory);\r\n\r\n // Log encoding attacks for security monitoring\r\n if (pathEncoding.detected) {\r\n // In production, this should trigger security alerts\r\n console.warn('Security: Encoding attack detected in path input', {\r\n originalInput: pathEncoding.originalInput,\r\n decodedOutput: pathEncoding.decodedOutput,\r\n iterationsRequired: pathEncoding.iterationsRequired,\r\n });\r\n }\r\n\r\n // Check for home directory expansion attempts on DECODED path\r\n if (decodedPath.startsWith('~') || decodedPath.includes('/~') || decodedPath.includes('\\\\~')) {\r\n throw new PathValidationError(\r\n 'Path validation failed: home directory access denied',\r\n {\r\n filePath,\r\n decodedPath,\r\n baseDirectory,\r\n reason: 'HOME_DIRECTORY_ACCESS',\r\n }\r\n );\r\n }\r\n\r\n // Check for home directory expansion attempts in baseDirectory\r\n if (decodedBase.startsWith('~')) {\r\n throw new PathValidationError(\r\n 'Base directory validation failed: home directory access denied',\r\n {\r\n baseDirectory,\r\n decodedBase,\r\n reason: 'BASE_HOME_DIRECTORY_ACCESS',\r\n }\r\n );\r\n }\r\n\r\n // Normalize the base directory first\r\n const normalizedBase = path.normalize(decodedBase);\r\n const resolvedBase = path.resolve(normalizedBase);\r\n\r\n // Normalize and resolve the file path relative to base\r\n // NOW normalized on already-decoded path to prevent encoding bypasses\r\n const normalizedPath = path.normalize(decodedPath);\r\n\r\n // Check if path contains suspicious patterns after normalization\r\n if (normalizedPath.includes('..') || normalizedPath === '.' || normalizedPath.includes('/./')) {\r\n throw new PathValidationError(\r\n 'Path validation failed: path contains directory traversal patterns',\r\n {\r\n filePath,\r\n decodedPath,\r\n normalizedPath,\r\n baseDirectory,\r\n reason: 'TRAVERSAL_PATTERN_DETECTED',\r\n }\r\n );\r\n }\r\n\r\n // Resolve the path relative to base directory\r\n const resolvedPath = path.resolve(resolvedBase, normalizedPath);\r\n\r\n // Check if resolved path is within base directory\r\n const isWithinBase = isPathWithinBase(resolvedPath, resolvedBase);\r\n\r\n if (!isWithinBase) {\r\n throw new PathValidationError(\r\n 'Path validation failed: resolved path is outside allowed directory',\r\n {\r\n filePath,\r\n resolvedPath,\r\n baseDirectory: resolvedBase,\r\n reason: 'PATH_OUTSIDE_BASE',\r\n }\r\n );\r\n }\r\n\r\n // Check for symlinks (prevents symlink attacks)\r\n let isSymlink = false;\r\n try {\r\n const stats = fs.lstatSync(resolvedPath);\r\n isSymlink = stats.isSymbolicLink();\r\n\r\n if (isSymlink) {\r\n throw new PathValidationError(\r\n 'Path validation failed: symbolic links are not allowed',\r\n {\r\n filePath,\r\n resolvedPath,\r\n reason: 'SYMLINK_NOT_ALLOWED',\r\n }\r\n );\r\n }\r\n } catch (error) {\r\n // File doesn't exist yet (expected for validation before creation)\r\n // or it's a symlink that was rejected above\r\n if (error instanceof PathValidationError) {\r\n throw error;\r\n }\r\n // Other errors (permission denied, etc.) are not path validation failures\r\n // The file validation happens later\r\n }\r\n\r\n return {\r\n valid: true,\r\n resolvedPath,\r\n normalizedPath,\r\n isWithinBase: true,\r\n isSymlink: false,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a path is within a base directory\r\n *\r\n * Uses path resolution and string comparison to ensure the resolved path\r\n * is actually within the base directory (not just sharing a prefix).\r\n *\r\n * @param filePath - The path to check\r\n * @param baseDirectory - The base directory\r\n * @returns True if filePath is within baseDirectory\r\n *\r\n * @example\r\n * isPathWithinBase('/home/user/project/src/file.ts', '/home/user/project') // true\r\n * isPathWithinBase('/home/user/project-evil/file.ts', '/home/user/project') // false\r\n */\r\nexport function isPathWithinBase(filePath: string, baseDirectory: string): boolean {\r\n // Ensure both paths are normalized and absolute\r\n const normalizedFile = path.normalize(path.resolve(filePath));\r\n const normalizedBase = path.normalize(path.resolve(baseDirectory));\r\n\r\n // Exact match\r\n if (normalizedFile === normalizedBase) {\r\n return true;\r\n }\r\n\r\n // Check if file is within base (use path.relative to ensure it's not going up)\r\n const relative = path.relative(normalizedBase, normalizedFile);\r\n\r\n // If relative path starts with \"..\", it's outside the base directory\r\n if (relative.startsWith('..')) {\r\n return false;\r\n }\r\n\r\n // If relative path is absolute, it's outside the base directory\r\n if (path.isAbsolute(relative)) {\r\n return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Validate multiple paths within the same base directory\r\n *\r\n * Efficiently validates multiple paths, returning results for each.\r\n *\r\n * @param filePaths - Array of file paths to validate\r\n * @param baseDirectory - The base directory that all files must reside within\r\n * @returns Map of file path to validation result\r\n *\r\n * @example\r\n * const results = validatePaths(['docs/SKILL.md', 'src/index.ts'], './.claude/skills');\r\n * results.forEach((result, filePath) => {\r\n * if (!result.valid) {\r\n * console.error(`Invalid path: ${filePath}`, result.reason);\r\n * }\r\n * });\r\n */\r\nexport function validatePaths(\r\n filePaths: string[],\r\n baseDirectory: string\r\n): Map<string, PathValidationResult> {\r\n const results = new Map<string, PathValidationResult>();\r\n\r\n for (const filePath of filePaths) {\r\n try {\r\n const result = validatePath(filePath, baseDirectory);\r\n results.set(filePath, result);\r\n } catch (error) {\r\n if (error instanceof PathValidationError) {\r\n results.set(filePath, {\r\n valid: false,\r\n resolvedPath: '',\r\n normalizedPath: '',\r\n isWithinBase: false,\r\n isSymlink: false,\r\n reason: error.context?.reason as string | undefined,\r\n });\r\n } else {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Get the safe path for a file (or throw if validation fails)\r\n *\r\n * Convenience function that validates and returns the resolved path,\r\n * or throws an error if validation fails.\r\n *\r\n * @param filePath - The file path to validate\r\n * @param baseDirectory - The base directory that file must reside within\r\n * @returns The resolved, validated absolute path\r\n * @throws PathValidationError if path validation fails\r\n *\r\n * @example\r\n * const safePath = getSafePath('docs/SKILL.md', './.claude/skills');\r\n * fs.readFileSync(safePath); // Safe to use\r\n */\r\nexport function getSafePath(filePath: string, baseDirectory: string): string {\r\n const result = validatePath(filePath, baseDirectory);\r\n return result.resolvedPath;\r\n}\r\n\r\n/**\r\n * Check if a path is considered safe for operations\r\n *\r\n * This is a non-throwing version of validatePath for conditional logic.\r\n *\r\n * @param filePath - The file path to check\r\n * @param baseDirectory - The base directory\r\n * @returns True if path is safe, false otherwise\r\n *\r\n * @example\r\n * if (isPathSafe(userInput, './.claude/skills')) {\r\n * // Process the file\r\n * } else {\r\n * // Reject the request\r\n * }\r\n */\r\nexport function isPathSafe(filePath: string, baseDirectory: string): boolean {\r\n try {\r\n validatePath(filePath, baseDirectory);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Get validation error details for a path (if invalid)\r\n *\r\n * Useful for logging and diagnostics.\r\n *\r\n * @param filePath - The file path to validate\r\n * @param baseDirectory - The base directory\r\n * @returns Error with details, or undefined if path is valid\r\n *\r\n * @example\r\n * const error = getPathValidationError('../../etc/passwd', './.claude/skills');\r\n * if (error) {\r\n * logger.error(error.message, error.context);\r\n * }\r\n */\r\nexport function getPathValidationError(\r\n filePath: string,\r\n baseDirectory: string\r\n): PathValidationError | undefined {\r\n try {\r\n validatePath(filePath, baseDirectory);\r\n return undefined;\r\n } catch (error) {\r\n if (error instanceof PathValidationError) {\r\n return error;\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * List allowed files within a base directory (safely)\r\n *\r\n * Recursively lists all files within base directory, validating\r\n * each path to ensure it's within bounds.\r\n *\r\n * @param baseDirectory - The base directory to scan\r\n * @param options - Options for listing (maxDepth, filter)\r\n * @returns Array of validated, safe paths relative to baseDirectory\r\n *\r\n * @example\r\n * const files = safeListDirectory('./.claude/skills');\r\n * files.forEach(file => {\r\n * // All paths are guaranteed safe\r\n * console.log(file);\r\n * });\r\n */\r\nexport function safeListDirectory(\r\n baseDirectory: string,\r\n options?: {\r\n maxDepth?: number;\r\n filter?: (path: string) => boolean;\r\n }\r\n): string[] {\r\n const safeFiles: string[] = [];\r\n const maxDepth = options?.maxDepth ?? Infinity;\r\n const filter = options?.filter ?? (() => true);\r\n\r\n function walkDirectory(dir: string, currentDepth: number = 0): void {\r\n if (currentDepth > maxDepth) {\r\n return;\r\n }\r\n\r\n try {\r\n const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n const relativePath = path.relative(baseDirectory, fullPath);\r\n\r\n // Validate the path is still within base\r\n if (!isPathWithinBase(fullPath, baseDirectory)) {\r\n continue;\r\n }\r\n\r\n // Apply filter\r\n if (!filter(relativePath)) {\r\n continue;\r\n }\r\n\r\n safeFiles.push(relativePath);\r\n\r\n // Recursively walk directories\r\n if (entry.isDirectory() && !entry.isSymbolicLink()) {\r\n walkDirectory(fullPath, currentDepth + 1);\r\n }\r\n }\r\n } catch (error) {\r\n // Silently skip directories we can't read (permission denied, etc.)\r\n }\r\n }\r\n\r\n walkDirectory(baseDirectory);\r\n return safeFiles;\r\n}\r\n"],"names":["path","fs","StandardError","PathValidationError","message","context","name","decodePathSafely","inputPath","decoded","previous","iterations","MAX_ITERATIONS","originalInput","invalidEncodingDetected","decodeURIComponent","error","decodedOutput","reason","encodingAttackDetected","normalized","normalize","includes","encoding","detected","type","undefined","iterationsRequired","validatePath","filePath","baseDirectory","decodedPath","pathEncoding","decodedBase","console","warn","startsWith","normalizedBase","resolvedBase","resolve","normalizedPath","resolvedPath","isWithinBase","isPathWithinBase","isSymlink","stats","lstatSync","isSymbolicLink","valid","normalizedFile","relative","isAbsolute","validatePaths","filePaths","results","Map","result","set","getSafePath","isPathSafe","getPathValidationError","safeListDirectory","options","safeFiles","maxDepth","Infinity","filter","walkDirectory","dir","currentDepth","entries","readdirSync","withFileTypes","entry","fullPath","join","relativePath","push","isDirectory"],"mappings":"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"}
|