@kendoo.agentdesk/agentdesk 0.22.0 → 0.22.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.
package/CHANGELOG.md CHANGED
@@ -13,6 +13,9 @@ Internal refactors, infrastructure changes, and architectural notes are not list
13
13
  ### Added
14
14
  - `[UI]` Private-session sharing flow. When someone visits a session URL they don't own, they now see a friendly "Shh… this one's private" page with a one-click "Request access" button instead of a blank error. The session owner sees pending requests in a new header inbox and can grant viewer access for just that session or the whole project. Viewer-granted sessions show up in the teammate's sidebar tagged as a viewer.
15
15
 
16
+ ### Changed
17
+ - `[Both]` Security improvements and hardening. No action required.
18
+
16
19
  ## [0.22.0] — 2026-05-23
17
20
 
18
21
  ### Changed
@@ -1,7 +1,12 @@
1
1
  // Verify tracker API permissions before starting a session
2
2
  // Checks: read tasks, create tasks, update tasks
3
3
 
4
- import { execSync } from "child_process";
4
+ import { execFileSync } from "child_process";
5
+
6
+ // AD-29: any external string (repo name, ref, etc.) must be regex-validated
7
+ // before it goes into a child process. Even with execFile, an upstream caller
8
+ // passing "../../etc" or similar can trip path semantics in the called tool.
9
+ const GITHUB_REPO_RE = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
5
10
 
6
11
  const LINEAR_API = "https://api.linear.app/graphql";
7
12
 
@@ -187,18 +192,25 @@ async function checkGitHub({ repo }, creds) {
187
192
  const env = { ...process.env };
188
193
  if (creds?.GITHUB_TOKEN) env.GH_TOKEN = creds.GITHUB_TOKEN;
189
194
 
190
- // Check if gh CLI is available
195
+ // AD-29: refuse anything that isn't a clean owner/repo before going near a
196
+ // subprocess. `repo` comes from server-pushed project settings, which an
197
+ // attacker could control via a chained takeover.
198
+ if (!GITHUB_REPO_RE.test(repo)) {
199
+ return { ok: false, errors: [`Invalid GitHub repo format: ${JSON.stringify(repo)} (expected "owner/name")`] };
200
+ }
201
+
202
+ // Check if gh CLI is available. execFileSync (no shell) — argv is static.
191
203
  try {
192
- execSync("gh --version", { stdio: "pipe" });
204
+ execFileSync("gh", ["--version"], { stdio: "pipe" });
193
205
  } catch {
194
206
  return { ok: false, errors: ["GitHub CLI (gh) is not installed — install it from https://cli.github.com"] };
195
207
  }
196
208
 
197
209
  // Check auth status and grab the authenticated login
198
210
  try {
199
- execSync("gh auth status", { stdio: "pipe", env });
211
+ execFileSync("gh", ["auth", "status"], { stdio: "pipe", env });
200
212
  try {
201
- const who = execSync(`gh api user --jq '{login: .login, name: .name}'`, { stdio: "pipe", encoding: "utf-8", env }).trim();
213
+ const who = execFileSync("gh", ["api", "user", "--jq", "{login: .login, name: .name}"], { stdio: "pipe", encoding: "utf-8", env }).trim();
202
214
  const j = JSON.parse(who);
203
215
  identity = { name: j.name || j.login, login: j.login };
204
216
  } catch {}
@@ -206,9 +218,9 @@ async function checkGitHub({ repo }, creds) {
206
218
  return { ok: false, errors: ["GitHub CLI is not authenticated — run 'gh auth login', or paste a GITHUB_TOKEN"] };
207
219
  }
208
220
 
209
- // Check repo access and permissions
221
+ // Check repo access and permissions — argv form, no shell, repo already validated.
210
222
  try {
211
- const result = execSync(`gh api repos/${repo} --jq ".permissions"`, { stdio: "pipe", encoding: "utf-8", env });
223
+ const result = execFileSync("gh", ["api", `repos/${repo}`, "--jq", ".permissions"], { stdio: "pipe", encoding: "utf-8", env });
212
224
  const perms = JSON.parse(result.trim());
213
225
 
214
226
  if (!perms.pull) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  "server": "node server/index.mjs",
23
23
  "build": "vite build",
24
24
  "preview": "vite preview",
25
- "test": "node --test tests/server.test.mjs tests/agents.test.mjs tests/homepage.test.mjs tests/sessionUtils.test.mjs tests/tracker-url.test.mjs tests/session-preflight.test.mjs tests/access.test.mjs",
25
+ "test": "node --test tests/server.test.mjs tests/agents.test.mjs tests/homepage.test.mjs tests/sessionUtils.test.mjs tests/tracker-url.test.mjs tests/session-preflight.test.mjs tests/access.test.mjs tests/project-ownership.test.mjs tests/random-hex.test.mjs",
26
26
  "lint:changelog": "node scripts/lint-changelog.mjs",
27
27
  "prepublishOnly": "node scripts/lint-changelog.mjs"
28
28
  },