groove-dev 0.27.26 → 0.27.28
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/.groove-staging/state.json +3 -0
- package/.groove-staging/timeline.json +13 -0
- package/CLAUDE.md +0 -10
- package/DECENTRALIZED_NET_WP_V1.md +871 -0
- package/README.md +28 -0
- package/SECURITY_SWEEP.md +228 -0
- package/decentralized-net/ACTION_PLAN.md +422 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +99 -0
- package/node_modules/@groove-dev/daemon/src/introducer.js +7 -7
- package/node_modules/@groove-dev/daemon/src/journalist.js +36 -6
- package/node_modules/@groove-dev/daemon/src/memory.js +29 -10
- package/node_modules/@groove-dev/daemon/src/process.js +29 -12
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +26 -1
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +34 -11
- package/node_modules/@groove-dev/daemon/src/rotator.js +24 -1
- package/node_modules/@groove-dev/daemon/test/introducer.test.js +63 -0
- package/node_modules/@groove-dev/daemon/test/journalist.test.js +106 -0
- package/node_modules/@groove-dev/daemon/test/memory.test.js +49 -0
- package/node_modules/@groove-dev/daemon/test/rotator.test.js +99 -0
- package/node_modules/@groove-dev/gui/dist/assets/{index-DieCV-v1.js → index-Ch1N9G4Z.js} +1728 -1728
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +147 -21
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +206 -44
- package/node_modules/@groove-dev/gui/src/components/marketplace/integration-wizard.jsx +11 -24
- package/node_modules/@groove-dev/gui/src/components/marketplace/marketplace-card.jsx +1 -36
- package/node_modules/@groove-dev/gui/src/lib/integration-logos.js +39 -0
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +99 -0
- package/packages/daemon/src/introducer.js +7 -7
- package/packages/daemon/src/journalist.js +36 -6
- package/packages/daemon/src/memory.js +29 -10
- package/packages/daemon/src/process.js +29 -12
- package/packages/daemon/src/providers/claude-code.js +26 -1
- package/packages/daemon/src/providers/codex.js +34 -11
- package/packages/daemon/src/rotator.js +24 -1
- package/packages/gui/dist/assets/{index-DieCV-v1.js → index-Ch1N9G4Z.js} +1728 -1728
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-config.jsx +147 -21
- package/packages/gui/src/components/agents/spawn-wizard.jsx +206 -44
- package/packages/gui/src/components/marketplace/integration-wizard.jsx +11 -24
- package/packages/gui/src/components/marketplace/marketplace-card.jsx +1 -36
- package/packages/gui/src/lib/integration-logos.js +39 -0
- package/MUST_FIX_ISSUES.md +0 -305
package/README.md
CHANGED
|
@@ -7,6 +7,20 @@ The open-source orchestration layer for AI coding tools. Spawn teams of agents,
|
|
|
7
7
|
[](https://www.npmjs.com/package/groove-dev)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
|
|
10
|
+
## Get Started
|
|
11
|
+
|
|
12
|
+
### Download the App
|
|
13
|
+
|
|
14
|
+
No terminal needed. Download, install, open a project folder.
|
|
15
|
+
|
|
16
|
+
- [**macOS** (.dmg)](https://github.com/grooveai-dev/groove/releases/latest) — Intel and Apple Silicon
|
|
17
|
+
- [**Windows** (.exe)](https://github.com/grooveai-dev/groove/releases/latest) — one-click installer
|
|
18
|
+
- [**Linux** (.AppImage)](https://github.com/grooveai-dev/groove/releases/latest) — x64 and ARM
|
|
19
|
+
|
|
20
|
+
Everything is bundled — daemon, GUI, auto-updates. No Node.js required.
|
|
21
|
+
|
|
22
|
+
### Developer Install
|
|
23
|
+
|
|
10
24
|
```bash
|
|
11
25
|
npm i -g groove-dev
|
|
12
26
|
groove start
|
|
@@ -16,6 +30,20 @@ The GUI opens at `http://localhost:31415`. On a VPS? groove detects it and tells
|
|
|
16
30
|
|
|
17
31
|
---
|
|
18
32
|
|
|
33
|
+
## Desktop App
|
|
34
|
+
|
|
35
|
+
The desktop app is the easiest way to use groove — no terminal, no dependencies, no setup.
|
|
36
|
+
|
|
37
|
+
- **Full GUI dashboard** — agent tree, chat, editor, telemetry, marketplace, all in one window
|
|
38
|
+
- **Bundled daemon** — starts automatically when you open a project, stops when you close it
|
|
39
|
+
- **System tray** — quick access to recent projects, daemon status, and controls
|
|
40
|
+
- **Automatic updates** — new versions install silently in the background
|
|
41
|
+
- **Multi-workspace** — open any project folder; manages one daemon per project
|
|
42
|
+
- **Platform support** — macOS (Intel + Apple Silicon), Windows (x64 + ARM64), Linux (x64 + ARM64)
|
|
43
|
+
- **No dependencies** — everything is bundled. No Node.js, no terminal knowledge needed
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
19
47
|
## The Problem
|
|
20
48
|
|
|
21
49
|
AI coding agents waste your money and lose their way:
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Security Sweep Report
|
|
2
|
+
|
|
3
|
+
Date: 2026-04-16
|
|
4
|
+
Assessor: Security audit
|
|
5
|
+
Scope reviewed: `../packages/desktop`, `../packages/gui`, `../packages/daemon`, root dependency graph in `../package-lock.json`
|
|
6
|
+
Note: the working directory `./` only contained handoff artifacts, so the actual Electron app code audited lives in the parent monorepo `../`.
|
|
7
|
+
|
|
8
|
+
## Executive Summary
|
|
9
|
+
|
|
10
|
+
Overall risk: **High**
|
|
11
|
+
|
|
12
|
+
The desktop app has several solid baseline controls in place — Electron windows run with `contextIsolation`, `sandbox`, and `nodeIntegration: false`; provider API keys are encrypted at rest; and file path handling includes symlink checks. However, I found **three high-impact architectural issues** that materially raise compromise risk:
|
|
13
|
+
|
|
14
|
+
1. **Project-controlled active content is served from the app's trusted origin**, creating a same-origin path to the daemon API.
|
|
15
|
+
2. **The daemon control plane is effectively unauthenticated**, with broad localhost trust and optional non-loopback binds.
|
|
16
|
+
3. **Browser-mode marketplace tokens can be persisted in plaintext config and then exposed by `/api/config`**.
|
|
17
|
+
|
|
18
|
+
These issues mean that a malicious repository, a hostile local webpage on `localhost`, or a reachable peer when bound to Tailscale/LAN can potentially read project data, mutate files, spawn processes/agents, and access local app state.
|
|
19
|
+
|
|
20
|
+
## Methodology
|
|
21
|
+
|
|
22
|
+
- Static review of Electron main/preload, renderer, and daemon code
|
|
23
|
+
- Targeted grep for OWASP-style sinks: XSS, injection, SSRF, auth bypass, unsafe file access, shell/process execution
|
|
24
|
+
- Review of secret storage and config persistence behavior
|
|
25
|
+
- Dependency check with `npm audit --json` and dependency resolution via `npm ls`
|
|
26
|
+
- Verification of packaging and ignore rules for runtime secrets/artifacts
|
|
27
|
+
|
|
28
|
+
## Findings
|
|
29
|
+
|
|
30
|
+
### 1) Critical — Untrusted project HTML/JS can execute with daemon origin
|
|
31
|
+
|
|
32
|
+
**Severity:** Critical
|
|
33
|
+
**Category:** XSS / trusted-origin content execution / privilege escalation
|
|
34
|
+
**Primary locations:**
|
|
35
|
+
- `../packages/gui/src/views/editor.jsx:165`
|
|
36
|
+
- `../packages/daemon/src/api.js:2274`
|
|
37
|
+
- `../packages/daemon/src/mimetypes.js:15`
|
|
38
|
+
- `../packages/daemon/src/mimetypes.js:17`
|
|
39
|
+
|
|
40
|
+
**What I found**
|
|
41
|
+
- The editor intentionally previews HTML files by loading `/api/files/raw?path=...` into an iframe: `../packages/gui/src/views/editor.jsx:165`.
|
|
42
|
+
- The daemon serves raw project files directly from the app origin and preserves executable MIME types such as `text/javascript` and `text/html`: `../packages/daemon/src/api.js:2274`, `../packages/daemon/src/mimetypes.js:15`, `../packages/daemon/src/mimetypes.js:17`.
|
|
43
|
+
- Because this content is delivered from the same origin as `/api/*`, any project-controlled HTML that gets rendered can execute JavaScript against the daemon API using the app's trusted origin.
|
|
44
|
+
|
|
45
|
+
**Why this matters**
|
|
46
|
+
A malicious repository can plant an `index.html` + `payload.js` pair. If the HTML preview path is reached, or if the raw file is otherwise navigated to from the trusted origin, the payload can:
|
|
47
|
+
- read or modify project files,
|
|
48
|
+
- spawn/kill agents,
|
|
49
|
+
- change daemon config,
|
|
50
|
+
- abuse local-only features exposed over HTTP/WS.
|
|
51
|
+
|
|
52
|
+
This is a classic Electron/browser trust-boundary failure: **workspace content should never run with the same origin as the privileged app UI**.
|
|
53
|
+
|
|
54
|
+
**Recommended fix**
|
|
55
|
+
- Do **not** serve active workspace content (`.html`, `.js`, `.mjs`, `.svg`, etc.) from the daemon's privileged origin.
|
|
56
|
+
- For previews, use one of these safer patterns:
|
|
57
|
+
- render sanitized HTML only,
|
|
58
|
+
- serve previews from a **separate origin** with no access to `/api/*`,
|
|
59
|
+
- use a dedicated isolated `BrowserWindow`/partition with no preload, no shared cookies/storage, and no privileged bridge,
|
|
60
|
+
- force dangerous types to download or be served as `text/plain`.
|
|
61
|
+
- Remove `allow-same-origin` from any preview iframe unless the content is fully trusted.
|
|
62
|
+
- Add regression tests that verify active content cannot call privileged API routes.
|
|
63
|
+
|
|
64
|
+
**Priority:** P0
|
|
65
|
+
|
|
66
|
+
### 2) High — Daemon HTTP/WebSocket control plane has no real authentication
|
|
67
|
+
|
|
68
|
+
**Severity:** High
|
|
69
|
+
**Category:** Authentication / access control / CSRF-adjacent localhost trust
|
|
70
|
+
**Primary locations:**
|
|
71
|
+
- `../packages/daemon/src/api.js:68`
|
|
72
|
+
- `../packages/daemon/src/api.js:120`
|
|
73
|
+
- `../packages/daemon/src/api.js:2223`
|
|
74
|
+
- `../packages/daemon/src/index.js:155`
|
|
75
|
+
- `../packages/daemon/src/index.js:169`
|
|
76
|
+
- `../packages/daemon/src/index.js:250`
|
|
77
|
+
- `../packages/daemon/src/index.js:451`
|
|
78
|
+
|
|
79
|
+
**What I found**
|
|
80
|
+
- The REST API trusts requests with **no `Origin` header** and also allows **any localhost origin**: `../packages/daemon/src/api.js:68`.
|
|
81
|
+
- Sensitive routes such as agent spawning and file deletion are exposed without any per-request auth token: `../packages/daemon/src/api.js:120`, `../packages/daemon/src/api.js:2223`.
|
|
82
|
+
- WebSocket upgrades also allow missing `Origin`, and accepted clients can request terminal spawns/input: `../packages/daemon/src/index.js:155`, `../packages/daemon/src/index.js:169`, `../packages/daemon/src/index.js:250`.
|
|
83
|
+
- The daemon can bind to non-loopback hosts, including Tailscale/LAN addresses: `../packages/daemon/src/index.js:451`.
|
|
84
|
+
|
|
85
|
+
**Why this matters**
|
|
86
|
+
This turns the daemon into a local control plane with weak trust assumptions:
|
|
87
|
+
- Any hostile local webpage served from `http://localhost:*` can make authenticated-by-origin reads/writes against the daemon.
|
|
88
|
+
- Any non-browser client can omit `Origin` entirely and still connect.
|
|
89
|
+
- If the daemon is started on a reachable interface (for example Tailscale/LAN), remote peers can hit powerful endpoints unless another network control blocks them.
|
|
90
|
+
|
|
91
|
+
Impact includes agent/process control, file mutation, editor/terminal access, config changes, and broader project compromise.
|
|
92
|
+
|
|
93
|
+
**Recommended fix**
|
|
94
|
+
- Require a **random per-instance bearer token** (or equivalent secret) for **all** HTTP and WebSocket traffic.
|
|
95
|
+
- Reject requests lacking that token, even from localhost.
|
|
96
|
+
- Narrow CORS to the exact GUI origin instead of `any localhost port`.
|
|
97
|
+
- Treat missing `Origin` as untrusted for browser-like endpoints.
|
|
98
|
+
- For non-loopback binds, require explicit auth plus network ACLs/TLS.
|
|
99
|
+
- Consider Unix domain sockets or loopback-only ephemeral tokens for desktop mode.
|
|
100
|
+
|
|
101
|
+
**Priority:** P0
|
|
102
|
+
|
|
103
|
+
### 3) High — Marketplace token can be stored plaintext and leaked through `/api/config`
|
|
104
|
+
|
|
105
|
+
**Severity:** High
|
|
106
|
+
**Category:** Secrets management / sensitive data exposure
|
|
107
|
+
**Primary locations:**
|
|
108
|
+
- `../packages/daemon/src/skills.js:47`
|
|
109
|
+
- `../packages/daemon/src/skills.js:80`
|
|
110
|
+
- `../packages/daemon/src/firstrun.js:145`
|
|
111
|
+
- `../packages/daemon/src/api.js:3438`
|
|
112
|
+
- `../packages/daemon/src/api.js:1115`
|
|
113
|
+
|
|
114
|
+
**What I found**
|
|
115
|
+
- The browser-style auth callback stores `marketplace.token` inside `daemon.config`: `../packages/daemon/src/api.js:1115`, `../packages/daemon/src/skills.js:80`.
|
|
116
|
+
- `saveConfig()` writes that config directly to `config.json` without encryption: `../packages/daemon/src/firstrun.js:145`.
|
|
117
|
+
- `/api/config` returns the full config object without redaction: `../packages/daemon/src/api.js:3438`.
|
|
118
|
+
|
|
119
|
+
**Why this matters**
|
|
120
|
+
Even though the Electron main process uses encrypted `safeStorage` for its own desktop token path, the daemon still contains a second browser-oriented auth flow that can persist a bearer token in plaintext config and then expose it over the local API.
|
|
121
|
+
|
|
122
|
+
If an attacker can hit the daemon API or read the `.groove` directory, they may recover the marketplace token and impersonate the user against Groove services.
|
|
123
|
+
|
|
124
|
+
**Recommended fix**
|
|
125
|
+
- Never persist auth/session tokens in `config.json`.
|
|
126
|
+
- Store marketplace/session tokens only in OS-backed secure storage.
|
|
127
|
+
- Redact sensitive config keys from `/api/config` before returning any response.
|
|
128
|
+
- Add a migration that strips existing `marketplace.token` values from historical configs.
|
|
129
|
+
|
|
130
|
+
**Priority:** P1
|
|
131
|
+
|
|
132
|
+
### 4) Medium — Renderer can trigger arbitrary external URLs for integration OAuth
|
|
133
|
+
|
|
134
|
+
**Severity:** Medium
|
|
135
|
+
**Category:** URL handling / privilege amplification
|
|
136
|
+
**Primary location:**
|
|
137
|
+
- `../packages/desktop/main.js:1004`
|
|
138
|
+
|
|
139
|
+
**What I found**
|
|
140
|
+
`integration-oauth-start` accepts an arbitrary `oauthUrl` from the renderer and passes it straight to `shell.openExternal()`.
|
|
141
|
+
|
|
142
|
+
**Why this matters**
|
|
143
|
+
By itself this requires renderer compromise, but in Electron this is still an important defense-in-depth boundary. If the renderer is ever compromised, an attacker can launch:
|
|
144
|
+
- arbitrary external websites,
|
|
145
|
+
- custom protocol handlers,
|
|
146
|
+
- local application handlers registered on the OS.
|
|
147
|
+
|
|
148
|
+
**Recommended fix**
|
|
149
|
+
- Validate `oauthUrl` against a strict allowlist derived from the integration registry.
|
|
150
|
+
- Allow only `https:` and known IdP domains.
|
|
151
|
+
- Deny custom schemes and `file:`/`javascript:`/unexpected handlers.
|
|
152
|
+
|
|
153
|
+
**Priority:** P2
|
|
154
|
+
|
|
155
|
+
### 5) Medium — Electron auto-approves all permissions for localhost content
|
|
156
|
+
|
|
157
|
+
**Severity:** Medium
|
|
158
|
+
**Category:** Least privilege / hardening gap
|
|
159
|
+
**Primary location:**
|
|
160
|
+
- `../packages/desktop/main.js:245`
|
|
161
|
+
|
|
162
|
+
**What I found**
|
|
163
|
+
The permission handlers explicitly allow microphone/media, but then also return `true` for any other permission as long as the requesting page is `localhost`/`127.0.0.1`.
|
|
164
|
+
|
|
165
|
+
**Why this matters**
|
|
166
|
+
Once renderer trust is broken, this widens impact by silently approving extra capabilities that were never intended for routine app operation.
|
|
167
|
+
|
|
168
|
+
**Recommended fix**
|
|
169
|
+
- Replace the implicit `allow all localhost permissions` behavior with an explicit allowlist.
|
|
170
|
+
- Deny by default.
|
|
171
|
+
- Log and review any denied permission requests during development.
|
|
172
|
+
|
|
173
|
+
**Priority:** P2
|
|
174
|
+
|
|
175
|
+
### 6) Moderate dependency advisory — `follow-redirects` header leak
|
|
176
|
+
|
|
177
|
+
**Severity:** Moderate
|
|
178
|
+
**Category:** Dependency / third-party risk
|
|
179
|
+
**Location:** transitive dependency path `@groove-dev/daemon -> @slack/bolt -> axios -> follow-redirects@1.15.11`
|
|
180
|
+
|
|
181
|
+
**What I found**
|
|
182
|
+
A fresh `npm audit --json` run on 2026-04-16 reported one advisory:
|
|
183
|
+
- `follow-redirects <= 1.15.11` — leaks custom authentication headers to cross-domain redirect targets.
|
|
184
|
+
|
|
185
|
+
Dependency resolution shows this arrives through:
|
|
186
|
+
- `@slack/bolt@4.7.0`
|
|
187
|
+
- `axios@1.15.0`
|
|
188
|
+
- `follow-redirects@1.15.11`
|
|
189
|
+
|
|
190
|
+
**Recommended fix**
|
|
191
|
+
- Upgrade to a dependency chain that pulls a fixed `follow-redirects` release.
|
|
192
|
+
- If immediate upgrade is blocked, audit all Slack/axios usage for redirect-following with sensitive headers.
|
|
193
|
+
|
|
194
|
+
**Priority:** P2
|
|
195
|
+
|
|
196
|
+
## Positive Controls Observed
|
|
197
|
+
|
|
198
|
+
These are good and worth keeping:
|
|
199
|
+
|
|
200
|
+
- Electron windows use `contextIsolation: true`, `nodeIntegration: false`, and `sandbox: true`: `../packages/desktop/main.js:227`
|
|
201
|
+
- Provider credentials are encrypted at rest with AES-256-GCM and `0600` file permissions: `../packages/daemon/src/credentials.js:1`
|
|
202
|
+
- File path validation checks traversal and resolves symlinks before access: `../packages/daemon/src/api.js:2021`
|
|
203
|
+
- The root ignore policy excludes `.env`, `.groove`, runtime bundles, and build artifacts from git: `../.gitignore:1`
|
|
204
|
+
- I did **not** find hardcoded secrets in tracked source during pattern scans.
|
|
205
|
+
|
|
206
|
+
## Remediation Plan
|
|
207
|
+
|
|
208
|
+
### Immediate (this week)
|
|
209
|
+
- Disable HTML preview or force dangerous file types to render as plain text/download.
|
|
210
|
+
- Add an auth token requirement to all daemon HTTP/WS endpoints.
|
|
211
|
+
- Redact `/api/config` and remove token persistence from daemon config.
|
|
212
|
+
- Patch the `follow-redirects` dependency chain.
|
|
213
|
+
|
|
214
|
+
### Short term
|
|
215
|
+
- Serve untrusted previews from a separate origin/partition.
|
|
216
|
+
- Tighten `shell.openExternal()` to strict allowlists only.
|
|
217
|
+
- Replace localhost-wide CORS trust with an exact-origin model.
|
|
218
|
+
- Lock Electron permission handling to a minimal explicit list.
|
|
219
|
+
|
|
220
|
+
### Verification to add after fixes
|
|
221
|
+
- Test that opening a repo-controlled HTML file cannot call `/api/agents`, `/api/files/*`, or `/api/config`.
|
|
222
|
+
- Test that requests without the daemon auth token fail for both REST and WS.
|
|
223
|
+
- Test that `/api/config` never returns secret-bearing fields.
|
|
224
|
+
- Re-run `npm audit --json` after dependency upgrades.
|
|
225
|
+
|
|
226
|
+
## Bottom Line
|
|
227
|
+
|
|
228
|
+
The app already has several good Electron hardening defaults, but the **same-origin preview design** and the **unauthenticated daemon control surface** currently dominate the risk profile. I would treat Findings 1 and 2 as release-blocking for environments where untrusted repositories or shared/local-network access are realistic.
|