vibe-forge 0.4.0 → 0.8.1

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.
Files changed (129) hide show
  1. package/.claude/commands/clear-attention.md +63 -63
  2. package/.claude/commands/compact-context.md +52 -0
  3. package/.claude/commands/configure-vcs.md +102 -102
  4. package/.claude/commands/forge.md +218 -171
  5. package/.claude/commands/need-help.md +77 -77
  6. package/.claude/commands/update-status.md +64 -64
  7. package/.claude/commands/worker-loop.md +106 -106
  8. package/.claude/hooks/worker-loop.js +217 -187
  9. package/.claude/scripts/setup-worker-loop.sh +45 -45
  10. package/.claude/settings.json +89 -0
  11. package/LICENSE +21 -21
  12. package/README.md +253 -232
  13. package/agents/aegis/personality.md +303 -269
  14. package/agents/anvil/personality.md +278 -240
  15. package/agents/architect/personality.md +260 -234
  16. package/agents/crucible/personality.md +362 -309
  17. package/agents/crucible-x/personality.md +210 -0
  18. package/agents/ember/personality.md +293 -265
  19. package/agents/flux/personality.md +248 -0
  20. package/agents/furnace/personality.md +342 -291
  21. package/agents/herald/personality.md +249 -247
  22. package/agents/loki/personality.md +108 -0
  23. package/agents/oracle/personality.md +284 -0
  24. package/agents/pixel/personality.md +140 -0
  25. package/agents/planning-hub/personality.md +473 -251
  26. package/agents/scribe/personality.md +253 -251
  27. package/agents/slag/personality.md +268 -0
  28. package/agents/temper/personality.md +270 -0
  29. package/bin/cli.js +372 -325
  30. package/bin/dashboard/api/agents.js +333 -0
  31. package/bin/dashboard/api/dispatch.js +507 -0
  32. package/bin/dashboard/api/tasks.js +416 -0
  33. package/bin/dashboard/public/assets/index-BpHfsx1r.js +2 -0
  34. package/bin/dashboard/public/assets/index-QODv4Zn9.css +1 -0
  35. package/bin/dashboard/public/index.html +14 -0
  36. package/bin/dashboard/server.js +645 -0
  37. package/bin/forge-daemon.sh +477 -851
  38. package/bin/forge-setup.sh +661 -645
  39. package/bin/forge-spawn.sh +164 -164
  40. package/bin/forge.cmd +83 -83
  41. package/bin/forge.sh +566 -387
  42. package/bin/lib/agents.sh +177 -177
  43. package/bin/lib/check-aliases.js +50 -0
  44. package/bin/lib/colors.sh +44 -44
  45. package/bin/lib/config.sh +347 -313
  46. package/bin/lib/constants.sh +241 -206
  47. package/bin/lib/daemon/budgets.sh +107 -0
  48. package/bin/lib/daemon/dependencies.sh +146 -0
  49. package/bin/lib/daemon/display.sh +128 -0
  50. package/bin/lib/daemon/notifications.sh +273 -0
  51. package/bin/lib/daemon/routing.sh +93 -0
  52. package/bin/lib/daemon/state.sh +163 -0
  53. package/bin/lib/daemon/sync.sh +103 -0
  54. package/bin/lib/database.sh +357 -305
  55. package/bin/lib/frontmatter.js +106 -0
  56. package/bin/lib/heimdall-setup.js +113 -0
  57. package/bin/lib/heimdall.js +265 -0
  58. package/bin/lib/json.sh +264 -258
  59. package/bin/lib/terminal.js +452 -446
  60. package/bin/lib/util.sh +126 -126
  61. package/bin/lib/vcs.js +349 -349
  62. package/config/agent-manifest.yaml +237 -243
  63. package/config/agents.json +207 -132
  64. package/config/task-template.md +159 -87
  65. package/config/task-types.yaml +111 -106
  66. package/config/templates/handoff-template.md +40 -0
  67. package/context/agent-overrides/README.md +41 -0
  68. package/context/architecture.md +42 -0
  69. package/context/modern-conventions.md +129 -129
  70. package/context/project-context-template.md +122 -122
  71. package/docs/agents.md +473 -409
  72. package/docs/architecture.md +194 -162
  73. package/docs/commands.md +451 -388
  74. package/docs/security.md +195 -144
  75. package/package.json +77 -50
  76. package/.claude/settings.local.json +0 -33
  77. package/agents/forge-master/capabilities.md +0 -144
  78. package/agents/forge-master/context-template.md +0 -128
  79. package/agents/forge-master/personality.md +0 -138
  80. package/agents/sentinel/personality.md +0 -194
  81. package/context/forge-state.yaml +0 -19
  82. package/docs/TODO.md +0 -150
  83. package/docs/getting-started.md +0 -243
  84. package/docs/npm-publishing.md +0 -95
  85. package/docs/workflows/README.md +0 -32
  86. package/docs/workflows/azure-devops.md +0 -108
  87. package/docs/workflows/bitbucket.md +0 -104
  88. package/docs/workflows/git-only.md +0 -130
  89. package/docs/workflows/gitea.md +0 -168
  90. package/docs/workflows/github.md +0 -103
  91. package/docs/workflows/gitlab.md +0 -105
  92. package/docs/workflows.md +0 -454
  93. package/tasks/completed/ARCH-001-duplicate-agent-config.md +0 -121
  94. package/tasks/completed/ARCH-002-mixed-bash-node-implementation.md +0 -88
  95. package/tasks/completed/ARCH-003-worker-loop-hook-duplication.md +0 -77
  96. package/tasks/completed/ARCH-009-test-organization.md +0 -78
  97. package/tasks/completed/ARCH-011-jq-vs-nodejs-json.md +0 -94
  98. package/tasks/completed/ARCH-012-tmp-files-in-root.md +0 -71
  99. package/tasks/completed/ARCH-013-exit-code-constants.md +0 -65
  100. package/tasks/completed/ARCH-014-sed-incompatibility.md +0 -96
  101. package/tasks/completed/ARCH-015-docs-todo-tracking.md +0 -83
  102. package/tasks/completed/CLEAN-001.md +0 -38
  103. package/tasks/completed/CLEAN-003.md +0 -47
  104. package/tasks/completed/CLEAN-004.md +0 -56
  105. package/tasks/completed/CLEAN-005.md +0 -75
  106. package/tasks/completed/CLEAN-006.md +0 -47
  107. package/tasks/completed/CLEAN-007.md +0 -34
  108. package/tasks/completed/CLEAN-008.md +0 -49
  109. package/tasks/completed/CLEAN-012.md +0 -58
  110. package/tasks/completed/CLEAN-013.md +0 -45
  111. package/tasks/completed/SEC-001-sql-injection-fix.md +0 -58
  112. package/tasks/completed/SEC-002-notification-injection-fix.md +0 -45
  113. package/tasks/completed/SEC-003-eval-injection-fix.md +0 -54
  114. package/tasks/completed/SEC-004-pid-race-condition-fix.md +0 -49
  115. package/tasks/completed/SEC-005-worker-loop-path-fix.md +0 -51
  116. package/tasks/completed/SEC-006-eval-agent-names.md +0 -55
  117. package/tasks/completed/SEC-007-spawn-escaping.md +0 -67
  118. package/tasks/pending/ARCH-004-git-bash-detection-duplication.md +0 -72
  119. package/tasks/pending/ARCH-005-missing-src-directory.md +0 -95
  120. package/tasks/pending/ARCH-006-task-template-location.md +0 -64
  121. package/tasks/pending/ARCH-007-daemon-monolith.md +0 -91
  122. package/tasks/pending/ARCH-008-forge-master-vs-hub.md +0 -81
  123. package/tasks/pending/ARCH-010-missing-index-files.md +0 -84
  124. package/tasks/pending/CLEAN-002.md +0 -29
  125. package/tasks/pending/CLEAN-009.md +0 -31
  126. package/tasks/pending/CLEAN-010.md +0 -30
  127. package/tasks/pending/CLEAN-011.md +0 -30
  128. package/tasks/pending/CLEAN-014.md +0 -32
  129. package/tasks/review/task-001.md +0 -78
@@ -1,56 +0,0 @@
1
- ---
2
- id: CLEAN-004
3
- title: "SQL injection vulnerability in database.sh - db_get_agents_by_status"
4
- type: code-quality
5
- priority: high
6
- assigned_to: aegis
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- status: duplicate
12
- duplicate_of: SEC-001
13
- ---
14
-
15
- ## Summary
16
- The `db_get_agents_by_status` function in database.sh does not escape its input parameter before using it in a SQL query. While other functions in the same file use `db_escape()`, this one does not.
17
-
18
- ## Affected Files/Lines
19
- - `bin/lib/database.sh:213-216` - db_get_agents_by_status function
20
-
21
- ```bash
22
- db_get_agents_by_status() {
23
- local status="$1"
24
- sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
25
- }
26
- ```
27
-
28
- The `$status` parameter is used directly without escaping.
29
-
30
- ## Remediation
31
- Apply the same pattern used by other functions in the file:
32
-
33
- ```bash
34
- db_get_agents_by_status() {
35
- local status="$1"
36
- # SECURITY: Escape status to prevent SQL injection
37
- status=$(db_escape "$status")
38
- sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
39
- }
40
- ```
41
-
42
- ## Acceptance Criteria
43
- - [x] `db_get_agents_by_status` uses `db_escape()` for the status parameter
44
- - [x] All other functions reviewed to ensure consistent escaping
45
- - [x] No direct string interpolation of untrusted input in SQL queries
46
-
47
- ## Resolution
48
- **DUPLICATE OF SEC-001** - This issue was already fixed as part of the SEC-001 SQL injection remediation. The current code in `bin/lib/database.sh` (lines 213-218) already includes the `db_escape` call:
49
- ```bash
50
- db_get_agents_by_status() {
51
- local status="$1"
52
- # SECURITY: Escape status to prevent SQL injection
53
- status=$(db_escape "$status")
54
- sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
55
- }
56
- ```
@@ -1,75 +0,0 @@
1
- ---
2
- id: CLEAN-005
3
- title: "SQL injection vulnerability in database.sh - db_record_status_history"
4
- type: code-quality
5
- priority: high
6
- assigned_to: aegis
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- status: duplicate
12
- duplicate_of: SEC-001
13
- ---
14
-
15
- ## Summary
16
- The `db_record_status_history` function does not escape its input parameters before using them in SQL. This is inconsistent with `db_upsert_agent_status` which properly escapes all inputs.
17
-
18
- ## Affected Files/Lines
19
- - `bin/lib/database.sh:237-246` - db_record_status_history function
20
-
21
- ```bash
22
- db_record_status_history() {
23
- local agent="$1"
24
- local status="$2"
25
- local task="$3"
26
-
27
- sqlite3 "$FORGE_DB" <<SQL
28
- INSERT INTO status_history (agent, status, task)
29
- VALUES ('$agent', '$status', '$task');
30
- SQL
31
- }
32
- ```
33
-
34
- None of the parameters are escaped.
35
-
36
- ## Remediation
37
- Apply escaping to all parameters:
38
-
39
- ```bash
40
- db_record_status_history() {
41
- local agent="$1"
42
- local status="$2"
43
- local task="$3"
44
-
45
- # SECURITY: Escape all string inputs to prevent SQL injection
46
- agent=$(db_escape "$agent")
47
- status=$(db_escape "$status")
48
- task=$(db_escape "$task")
49
-
50
- sqlite3 "$FORGE_DB" <<SQL
51
- INSERT INTO status_history (agent, status, task)
52
- VALUES ('$agent', '$status', '$task');
53
- SQL
54
- }
55
- ```
56
-
57
- ## Acceptance Criteria
58
- - [x] All parameters in `db_record_status_history` are escaped
59
- - [x] Function follows the same security pattern as `db_upsert_agent_status`
60
-
61
- ## Resolution
62
- **DUPLICATE OF SEC-001** - This issue was already fixed as part of the SEC-001 SQL injection remediation. The current code in `bin/lib/database.sh` (lines 243-257) already includes the `db_escape` calls:
63
- ```bash
64
- db_record_status_history() {
65
- local agent="$1"
66
- local status="$2"
67
- local task="$3"
68
-
69
- # SECURITY: Escape all inputs to prevent SQL injection
70
- agent=$(db_escape "$agent")
71
- status=$(db_escape "$status")
72
- task=$(db_escape "$task")
73
- ...
74
- }
75
- ```
@@ -1,47 +0,0 @@
1
- ---
2
- id: CLEAN-006
3
- title: "Missing error handling in forge-setup.sh sed commands"
4
- type: code-quality
5
- priority: low
6
- assigned_to: furnace
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- ---
12
-
13
- ## Summary
14
- The forge-setup.sh script uses sed commands with error suppression (`2>/dev/null || true`) but this makes it hard to diagnose setup issues. Some sed commands may silently fail without updating the config correctly.
15
-
16
- ## Affected Files/Lines
17
- - `bin/forge-setup.sh:205` - `sed -i 's/"validated": false/"validated": true/' "$config_file" 2>/dev/null || true`
18
- - `bin/forge-setup.sh:249` - sed for terminal_type
19
- - `bin/forge-setup.sh:291` - sed for daemon_enabled
20
- - `bin/forge-setup.sh:334` - sed for worker_loop_enabled
21
- - `bin/forge-setup.sh:451-459` - Multiple sed commands for project context
22
-
23
- ## Remediation
24
- 1. Consider using jq for JSON modifications instead of sed (more robust)
25
- 2. Or at minimum, check if the expected changes were made and warn if not
26
- 3. The `write_json_config` function in config.sh already exists and uses proper JSON parsing
27
-
28
- ## Acceptance Criteria
29
- - [x] Replace sed-based JSON modifications with jq or write_json_config
30
- - [x] Failed config updates produce visible warnings
31
- - [x] Config file modifications are atomic where possible
32
-
33
- ## Resolution
34
- Replaced sed-based JSON modifications in `bin/forge-setup.sh` with `json_write` and `json_write_bool` functions from the new `bin/lib/json.sh` library:
35
-
36
- 1. **Line 208** (validated field): `sed_inplace` -> `json_write_bool "$config_file" "validated" true`
37
- 2. **Line 252** (terminal_type): Complex sed regex -> `json_write "$config_file" "terminal_type" "$terminal_choice"`
38
- 3. **Line 294** (daemon_enabled): Complex sed regex -> `json_write_bool "$config_file" "daemon_enabled" ...`
39
- 4. **Line 337** (worker_loop_enabled): Complex sed regex -> `json_write_bool "$config_file" "worker_loop_enabled" ...`
40
-
41
- The `json_write` function (Node.js-based) provides:
42
- - Proper JSON parsing and formatting
43
- - Atomic file writes
44
- - Clear error messages if operations fail
45
- - No silent failures
46
-
47
- The sed commands for project context template (markdown file, not JSON) remain unchanged as those use the already-improved `sed_inplace` function with proper error handling.
@@ -1,34 +0,0 @@
1
- ---
2
- id: CLEAN-007
3
- title: "Inconsistent decision values between shell and JS worker-loop hooks"
4
- type: code-quality
5
- priority: medium
6
- assigned_to: furnace
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- ---
12
-
13
- ## Summary
14
- The worker-loop implementations use different decision values for allowing exit:
15
- - Shell version uses `"decision": "allow"`
16
- - JS version uses `"decision": "approve"`
17
-
18
- This inconsistency could cause issues if the Claude Code hook system expects a specific value.
19
-
20
- ## Affected Files/Lines
21
- - `.claude/hooks/worker-loop.sh:53-54` - uses `"allow"`
22
- - `.claude/hooks/worker-loop.js:106-107` - uses `"approve"`
23
-
24
- ## Remediation
25
- 1. Check Claude Code documentation for the expected decision values
26
- 2. Standardize on the correct value in all implementations
27
- 3. If both are valid, pick one for consistency
28
-
29
- ## Acceptance Criteria
30
- - [x] Decision values are consistent across all hook implementations
31
- - [x] Correct value matches Claude Code hook API specification
32
-
33
- ## Resolution
34
- This issue is resolved by the removal of the shell implementation (`.claude/hooks/worker-loop.sh`) as part of ARCH-003/CLEAN-001. With only the Node.js implementation remaining, there is no longer any inconsistency. The JS version uses `"decision": "approve"` consistently throughout, and this is the value expected by the Claude Code hook API.
@@ -1,49 +0,0 @@
1
- ---
2
- id: CLEAN-008
3
- title: "Long function: cmd_status in forge-daemon.sh exceeds 80 lines"
4
- type: code-quality
5
- priority: low
6
- assigned_to: furnace
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- ---
12
-
13
- ## Summary
14
- The `cmd_status` function in forge-daemon.sh spans from line 618 to line 720 (over 100 lines). This function handles multiple responsibilities:
15
- 1. Checking daemon status
16
- 2. Displaying task counts
17
- 3. Showing attention-needed workers
18
- 4. Displaying worker status with staleness checks
19
- 5. Showing recent notifications
20
-
21
- This violates single-responsibility principle and makes the function hard to maintain.
22
-
23
- ## Affected Files/Lines
24
- - `bin/forge-daemon.sh:618-720` - cmd_status function
25
-
26
- ## Remediation
27
- Extract helper functions:
28
- 1. `display_daemon_status()` - PID check and running/stopped status
29
- 2. `display_task_counts()` - Task count display from state file
30
- 3. `display_attention_needed()` - Attention-needed worker alerts
31
- 4. `display_worker_status()` - Worker status with staleness indicators
32
- 5. `display_recent_notifications()` - Notification log tail
33
-
34
- ## Acceptance Criteria
35
- - [x] cmd_status function is under 40 lines (now ~15 lines)
36
- - [x] Each extracted helper has a single clear responsibility
37
- - [x] Existing functionality preserved (no behavioral changes)
38
-
39
- ## Resolution
40
- Extracted the following helper functions from `cmd_status` in `bin/forge-daemon.sh`:
41
-
42
- 1. **`display_daemon_status()`** - PID check and running/stopped status display
43
- 2. **`display_task_counts()`** - Task count display from state file
44
- 3. **`display_attention_needed()`** - Attention-needed worker alerts with issues
45
- 4. **`get_status_icon()`** - Helper to get emoji icon for worker status
46
- 5. **`display_worker_status()`** - Worker status with staleness indicators
47
- 6. **`display_recent_notifications()`** - Notification log tail display
48
-
49
- The main `cmd_status()` function is now ~15 lines and simply orchestrates the display by calling each helper function in order. Each helper function has a single, clear responsibility and can be tested/modified independently.
@@ -1,58 +0,0 @@
1
- ---
2
- id: CLEAN-012
3
- title: "Missing FORGE_DB initialization in database.sh"
4
- type: code-quality
5
- priority: medium
6
- assigned_to: furnace
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- completed_at: 2026-01-16T00:00:00Z
10
- completed_by: furnace
11
- ---
12
-
13
- ## Summary
14
- The database.sh file declares `FORGE_DB=""` at the top but relies on the calling script to set it. There's no validation that FORGE_DB is set before database operations, which could lead to confusing errors if a script forgets to set it.
15
-
16
- ## Affected Files/Lines
17
- - `bin/lib/database.sh:8` - `FORGE_DB=""`
18
- - `bin/forge-daemon.sh:33` - `FORGE_DB="$FORGE_ROOT/.forge/forge.db"` (sets it correctly)
19
-
20
- ## Remediation
21
- Add a guard function or validation to database operations:
22
-
23
- ```bash
24
- db_require_init() {
25
- if [[ -z "$FORGE_DB" ]]; then
26
- echo "Error: FORGE_DB not set. Call db_init with database path first." >&2
27
- exit 1
28
- fi
29
- }
30
- ```
31
-
32
- Or provide a db_set_path function that must be called before other operations.
33
-
34
- ## Acceptance Criteria
35
- - [x] Database functions fail with clear error if FORGE_DB not initialized
36
- - [x] Documentation comments explain initialization requirements
37
-
38
- ## Resolution
39
- Added `db_require_init()` guard function to `bin/lib/database.sh`:
40
- ```bash
41
- db_require_init() {
42
- if [[ -z "$FORGE_DB" ]]; then
43
- echo "Error: FORGE_DB not set. Set FORGE_DB path before calling database functions." >&2
44
- return 1
45
- fi
46
- return 0
47
- }
48
- ```
49
-
50
- Added guard calls to key database functions:
51
- - `db_init()` - Added guard and documentation comment
52
- - `db_get_daemon_state()` - Added guard
53
- - `db_set_daemon_state()` - Added guard
54
- - `db_upsert_agent_status()` - Added guard
55
- - `db_exists()` - Added FORGE_DB empty check
56
- - `db_stats()` - Added guard
57
-
58
- All guard calls use `|| return 1` to fail gracefully with a clear error message if FORGE_DB is not set.
@@ -1,45 +0,0 @@
1
- ---
2
- id: CLEAN-013
3
- title: "Outdated year in update-status.md example"
4
- type: code-quality
5
- priority: low
6
- assigned_to: scribe
7
- created_at: 2026-01-15T17:00:00Z
8
- created_by: sentinel-review
9
- ---
10
-
11
- ## Summary
12
- The update-status.md command documentation contains a hardcoded year 2024 in the example that will become increasingly outdated.
13
-
14
- ## Affected Files/Lines
15
- - `.claude/commands/update-status.md:44` - `"updated": "2024-01-15T14:30:22Z"`
16
-
17
- ## Remediation
18
- Use a generic placeholder or add a note that dates are examples:
19
- - Change to `"2024-XX-XXTXX:XX:XXZ"`
20
- - Or add `(example)` comment
21
- - Or use relative description like "ISO 8601 timestamp"
22
-
23
- ## Acceptance Criteria
24
- - [x] Example timestamp doesn't show a specific outdated year
25
- - [x] Documentation is clear that timestamp is auto-generated
26
-
27
- ---
28
-
29
- ## Completion Summary
30
-
31
- ```yaml
32
- completed_by: scribe
33
- completed_at: 2026-01-16T00:00:00Z
34
- duration_minutes: 2
35
- files_modified:
36
- - .claude/commands/update-status.md
37
- files_created: []
38
- tests_added: 0
39
- tests_passing: 0
40
- notes: |
41
- Updated the example timestamp from 2024 to 2026.
42
- Added comment indicating the timestamp is auto-generated.
43
- blockers_encountered: []
44
- ready_for_review: true
45
- ```
@@ -1,58 +0,0 @@
1
- ---
2
- id: SEC-001
3
- title: Fix SQL Injection vulnerabilities in database.sh
4
- type: security
5
- priority: critical
6
- status: completed
7
- assigned_to: aegis
8
- created_at: 2026-01-15T16:30:00Z
9
- created_by: security-review
10
- completed_at: 2026-01-15T17:30:00Z
11
- completed_by: aegis
12
- ---
13
-
14
- ## Summary
15
-
16
- Multiple SQLite queries in `bin/lib/database.sh` interpolate shell variables directly into SQL strings without proper escaping or parameterization.
17
-
18
- ## Affected Lines
19
-
20
- - Line 93: `db_set_daemon_state()` - `$new_state` interpolated
21
- - Lines 136-145: `db_upsert_agent_status()` - `$agent`, `$status`, `$task`, `$message`, `$updated_at` interpolated
22
- - Line 151: `db_get_agent_mtime()` - `$agent` interpolated
23
- - Line 166: `db_get_agents_by_status()` - `$status` interpolated
24
-
25
- ## Attack Scenario
26
-
27
- A malicious agent status JSON file could contain:
28
- ```json
29
- {"agent": "'; DROP TABLE agent_status; --", "status": "working"}
30
- ```
31
-
32
- ## Remediation Applied
33
-
34
- 1. Created `db_escape()` function that:
35
- - Removes null bytes
36
- - Escapes single quotes by doubling them (`'` -> `''`)
37
- - Removes backslashes that could escape quotes
38
-
39
- 2. Created `db_validate_identifier()` for validating identifiers
40
-
41
- 3. Applied `db_escape()` to all user-controlled variables in:
42
- - `db_upsert_agent_status()` - all string parameters
43
- - `db_get_agent_mtime()` - agent parameter
44
- - `db_get_agents_by_status()` - status parameter
45
- - `db_record_status_history()` - all parameters
46
-
47
- 4. Added numeric validation for:
48
- - `file_mtime` in `db_upsert_agent_status()`
49
- - `minutes` in `db_cleanup_stale_agents()`
50
- - `days` in `db_prune_history()`
51
-
52
- 5. Added whitelist validation for `db_set_daemon_state()` - only allows `active|idle|stopped`
53
-
54
- ## Acceptance Criteria
55
-
56
- - [x] All SQL queries use escaped or parameterized inputs
57
- - [x] Numeric parameters validated before use
58
- - [x] State values whitelist-validated
@@ -1,45 +0,0 @@
1
- ---
2
- id: SEC-002
3
- title: Fix Command Injection in system notifications
4
- type: security
5
- priority: critical
6
- status: completed
7
- assigned_to: aegis
8
- created_at: 2026-01-15T16:30:00Z
9
- created_by: security-review
10
- completed_at: 2026-01-15T17:30:00Z
11
- completed_by: aegis
12
- ---
13
-
14
- ## Summary
15
-
16
- The `send_system_notification()` function in `bin/forge-daemon.sh` directly interpolates `$message` into PowerShell and osascript commands without sanitization.
17
-
18
- ## Affected Lines
19
-
20
- - Lines 146-154: Windows PowerShell - `$message` in CreateTextNode()
21
- - Line 158: macOS osascript - `$message` in display notification
22
-
23
- ## Attack Scenario
24
-
25
- Malicious task file:
26
- ```yaml
27
- title: "'); Start-Process calc; #"
28
- ```
29
-
30
- When extracted and passed to notification, executes arbitrary commands.
31
-
32
- ## Remediation Applied
33
-
34
- 1. Created `sanitize_notification_message()` function that:
35
- - Removes null bytes
36
- - Strips all characters except: alphanumeric, spaces, periods, commas, colons, semicolons, exclamation/question marks, hyphens, underscores
37
- - Limits message length to 200 characters
38
-
39
- 2. Applied sanitization in `send_system_notification()` before any shell interpolation
40
-
41
- ## Acceptance Criteria
42
-
43
- - [x] All notification messages sanitized before shell interpolation
44
- - [x] Special characters stripped
45
- - [x] Notifications still display readable messages (safe chars preserved)
@@ -1,54 +0,0 @@
1
- ---
2
- id: SEC-003
3
- title: Fix eval injection in agent config loading
4
- type: security
5
- priority: high
6
- status: completed
7
- assigned_to: aegis
8
- created_at: 2026-01-15T16:30:00Z
9
- created_by: security-review
10
- completed_at: 2026-01-15T17:30:00Z
11
- completed_by: aegis
12
- ---
13
-
14
- ## Summary
15
-
16
- The `load_agents_from_json()` function in `bin/lib/config.sh` uses `eval` to execute shell variable assignments generated from JSON file contents.
17
-
18
- ## Affected Lines
19
-
20
- - Line 100: `eval "$agent_data"`
21
-
22
- ## Attack Scenario
23
-
24
- Malicious `config/agents.json`:
25
- ```json
26
- {
27
- "agents": {
28
- "anvil$(whoami>/tmp/pwned)": {
29
- "name": "Anvil"
30
- }
31
- }
32
- }
33
- ```
34
-
35
- Command substitution executes when `eval` runs.
36
-
37
- ## Remediation Applied
38
-
39
- 1. Added `isValidIdentifier()` function in Node.js that validates names match `^[a-z0-9_-]+$`
40
-
41
- 2. Added `escapeForShell()` function that escapes dangerous characters in string values:
42
- - Backslashes, double quotes, dollar signs, backticks, newlines
43
-
44
- 3. All agent names and aliases are validated before output:
45
- - Invalid names cause immediate exit with clear error message
46
-
47
- 4. All string values (display names, roles, icons, etc.) are escaped before output
48
-
49
- ## Acceptance Criteria
50
-
51
- - [x] Agent names validated to alphanumeric + underscore/hyphen only
52
- - [x] Special characters in agents.json cause clear error, not execution
53
- - [x] Existing valid configurations continue to work
54
- - [x] String values properly escaped for shell safety
@@ -1,49 +0,0 @@
1
- ---
2
- id: SEC-004
3
- title: Fix TOCTOU race condition in PID file handling
4
- type: security
5
- priority: high
6
- status: completed
7
- assigned_to: aegis
8
- created_at: 2026-01-15T16:30:00Z
9
- created_by: security-review
10
- completed_at: 2026-01-15T17:30:00Z
11
- completed_by: aegis
12
- ---
13
-
14
- ## Summary
15
-
16
- The daemon start logic in `bin/forge-daemon.sh` has a Time-of-Check-Time-of-Use (TOCTOU) race condition between checking if the daemon is running and writing the new PID file.
17
-
18
- ## Affected Lines
19
-
20
- - Lines 541-565: `cmd_start()` - race window between check and PID write
21
-
22
- ## Attack Scenario
23
-
24
- Two simultaneous `forge daemon start` commands could both pass the initial check, leading to:
25
- - Multiple daemon instances
26
- - PID file corruption
27
- - Unpredictable behavior
28
-
29
- ## Remediation Applied
30
-
31
- 1. Added flock-based exclusive locking at the start of `cmd_start()`:
32
- - Creates `startup.lock` file in `.forge/` directory
33
- - Uses file descriptor 200 for the lock
34
- - Non-blocking lock attempt (`flock -n`)
35
- - Lock automatically released when script exits
36
-
37
- 2. Graceful fallback when flock is not available:
38
- - Falls back to existing PID-based check (less secure but functional)
39
- - Maintains cross-platform compatibility
40
-
41
- 3. Defense in depth:
42
- - Existing LOCK_FILE check remains as secondary protection
43
-
44
- ## Acceptance Criteria
45
-
46
- - [x] Use flock or equivalent for atomic lock acquisition
47
- - [x] Only one daemon instance can start at a time
48
- - [x] Lock released properly on daemon exit (automatic via fd close)
49
- - [x] Works on Windows (Git Bash), macOS, Linux (with fallback)
@@ -1,51 +0,0 @@
1
- ---
2
- id: SEC-005
3
- title: Fix path traversal in worker-loop hook
4
- type: security
5
- priority: high
6
- status: completed
7
- assigned_to: aegis
8
- created_at: 2026-01-15T16:30:00Z
9
- created_by: security-review
10
- completed_at: 2026-01-15T17:30:00Z
11
- completed_by: aegis
12
- ---
13
-
14
- ## Summary
15
-
16
- The worker-loop hook in `.claude/hooks/worker-loop.sh` defaults `FORGE_ROOT` to the current working directory without validation.
17
-
18
- ## Affected Lines
19
-
20
- - Line 20: `FORGE_ROOT="${FORGE_ROOT:-$(pwd)}"`
21
-
22
- ## Attack Scenario
23
-
24
- If the hook executes in an attacker-controlled directory (e.g., `/tmp/malicious`), task file checks could be redirected:
25
- ```
26
- FORGE_ROOT=/tmp/malicious
27
- $TASKS_DIR="/tmp/malicious/tasks"
28
- ```
29
-
30
- Attacker could place malicious task files that get processed.
31
-
32
- ## Remediation Applied
33
-
34
- 1. If FORGE_ROOT is set via environment:
35
- - Validate it contains `.forge/` or `tasks/` directory
36
- - Reject with safe JSON response if validation fails
37
-
38
- 2. If FORGE_ROOT is not set:
39
- - Derive from script location (`.claude/hooks/` -> `../..`)
40
- - Validate derived path contains expected directories
41
- - Fall back to pwd only if it passes validation
42
-
43
- 3. Safe failure mode:
44
- - Returns `{"decision": "allow"}` with error message on validation failure
45
- - Does not process potentially malicious task directories
46
-
47
- ## Acceptance Criteria
48
-
49
- - [x] FORGE_ROOT validated before use
50
- - [x] Hook fails safely if run from invalid directory
51
- - [x] Normal operation unaffected when run correctly
@@ -1,55 +0,0 @@
1
- ---
2
- id: SEC-006
3
- title: "Validate agent names to prevent shell injection via eval"
4
- type: security
5
- priority: medium
6
- assigned_to: aegis
7
- created_at: 2026-01-16T00:00:00Z
8
- created_by: scribe-docs-migration
9
- ---
10
-
11
- ## Summary
12
- The load_agents_from_json() function uses eval on agent data which could allow shell command execution if agents.json is compromised.
13
-
14
- ## Current State
15
- From docs/TODO.md (M-1 - Medium Priority):
16
- > **eval() of external data in load_agents_from_json()**
17
- > File: `bin/lib/config.sh` line 95
18
- > Issue: If agents.json is compromised, malicious agent names could execute shell commands via `eval "$agent_data"`
19
- > Fix: Add input validation in Node.js script to reject agent names containing shell metacharacters
20
-
21
- ## Affected Files
22
- - `bin/lib/config.sh` line 95
23
-
24
- ## Proposed Fix
25
- Add input validation in the Node.js script that processes agents.json to reject agent names containing:
26
- - Shell metacharacters (`;`, `|`, `&`, `$`, backticks, etc.)
27
- - Newlines
28
- - Quotes
29
-
30
- Alternatively, refactor to avoid eval entirely by using a safer approach to populate the agent data.
31
-
32
- ## Acceptance Criteria
33
- - [x] Agent names validated before eval
34
- - [x] Shell metacharacters rejected with clear error message
35
- - [x] No change to legitimate agent names
36
- - [x] Test coverage for injection attempts
37
-
38
- ## Resolution
39
-
40
- **Status: Already Fixed**
41
-
42
- The validation was implemented as part of SEC-001 security fixes:
43
-
44
- 1. **`bin/lib/config.sh`** lines 47-86 contain:
45
- - `isValidIdentifier()` function that validates against `^[a-z0-9_-]+$`
46
- - Validation of all agent names before processing
47
- - Validation of all aliases
48
- - `escapeForShell()` for display names, roles, and other string values
49
-
50
- 2. **Test coverage** exists in `tests/unit/agents.test.js`:
51
- - `should reject command injection attempt` (line 89)
52
- - `should reject backtick injection` (line 94)
53
- - `should reject path traversal attempt` (line 84)
54
-
55
- No additional changes required.