Skip to content

Security fixes combined (#243-#252) — staging test#263

Open
jessie-coco wants to merge 11 commits intodevelopfrom
security-fixes-combined
Open

Security fixes combined (#243-#252) — staging test#263
jessie-coco wants to merge 11 commits intodevelopfrom
security-fixes-combined

Conversation

@jessie-coco
Copy link
Contributor

Summary

Combined branch merging all 9 security fix PRs for staging E2E testing before individual merges.

Included PRs

# Issue Branch PR
1 #243 — SQL injection in tag query fix/243-sql-injection-tag-query #254
2 #244 — V1 API access control fix/244-v1-api-access-control #257
3 #245 — Sidepanel XSS fix/245-sidepanel-xss #256
4 #246 — Auth token exposure fix/246-auth-token-exposure #255
5 #248 — Dispatch log null check fix/248-dispatch-log-null-check #258
6 #249 — Dockerignore security fix/249-dockerignore-security #259
7 #250 — Discussion race condition fix/250-discussion-race-condition #260
8 #251 — Adapters auth encryption fix/251-adapters-auth-encryption #261
9 #252 — Dashboard XSS & credentials fix/252-dashboard-xss-credentials #262

Purpose

This PR is for staging E2E testing only. It combines all security fixes into a single branch so they can be validated together before merging the individual PRs.

Do NOT close the original PRs. After staging validation passes, the individual PRs should be merged separately into develop.

Conflict Resolution

One conflict in dashboard/src/main.js was resolved by keeping the security fix (removing extension auth token sync, per #246).

boot-coco and others added 11 commits March 10, 2026 03:37
Replace LIKE pattern matching with SQLite json_each() for proper JSON
array searching. The previous approach interpolated the tag parameter
into a LIKE pattern, allowing SQL wildcards (%, _) and double-quotes
to alter query semantics and leak data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restrict externally_connectable localhost to port 3462 only
- GET_AUTH_STATE: return { authenticated, user } instead of raw JWT token
- DASHBOARD_LOGIN: validate token with server before accepting
- Dashboard: remove extension token auto-sync (use own OAuth flow)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add single-quote escaping to escapeHtml() (&#39;)
- Escape err.message in error handlers (lines 119, 137)
- Escape item.type, item.status, item.priority, item.created_by in list and thread views
- Escape item.id in data-id attribute

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
V1 item handlers (handleGetItem, handleAddMessage, handleAssignItem,
handleResolveItem, handleVerifyItem, handleReopenItem, handleCloseItem,
handleRespondToItem) did not verify that the requested item belongs to
the authenticated user's app_id. This allowed any authenticated user to
read, modify, or close items belonging to other apps.

Add the same app_id scoping check used by V2 endpoints:
  if (req.v2Auth?.app_id && item.app_id !== req.v2Auth.app_id)
    → 403 Forbidden

For handlers that previously skipped the item fetch (assign, resolve,
verify, reopen, close), an explicit getItem() call is added before the
scope check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
V1 item handlers (handleGetItem, handleAddMessage, handleAssignItem,
handleResolveItem, handleVerifyItem, handleReopenItem, handleCloseItem,
handleRespondToItem) did not verify that the requested item belongs to
the authenticated user's app_id. This allowed any authenticated user to
read, modify, or close items belonging to other apps.

Add the same app_id scoping check used by V2 endpoints:
  if (req.v2Auth?.app_id && item.app_id !== req.v2Auth.app_id)
    → 403 Forbidden

For handlers that previously skipped the item fetch (assign, resolve,
verify, reopen, close), an explicit getItem() call is added before the
scope check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both GET /api/v2/distributions/:item_id and POST .../retry had a flawed
access check that only ran when `item` was truthy. When an item was
deleted (null), the check was skipped entirely, leaking dispatch logs
and allowing retry triggers for any authenticated user.

Add an explicit null check before the access control guard so deleted
items return 404 immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
)

- Create .dockerignore to exclude .git, .env, config.json, data/, *.db,
  test/, node_modules/, extension/, docs/, and *.zip from Docker image
- Add non-root clawmark user in Dockerfile to reduce container blast radius

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oss (#250)

Add an in-memory per-document mutex (promise chain) that serializes all
read-modify-write operations on discussion JSON files. All four mutating
endpoints (POST /discussions, POST /respond, POST /discussions/resolve,
POST /submit-reply) are now wrapped in withDiscussionLock(doc, fn) so
concurrent requests on the same document are queued instead of racing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add v2Auth middleware to GET /api/v2/adapters (was unauthenticated)
- Encrypt endpoint configs at rest using the same encrypt/decrypt pattern
  already used for user_auths credentials
- Decrypt on read in getEndpoint, getEndpoints, updateEndpoint, setEndpointDefault

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ing (#252)

- Validate URL scheme (https?://) before window.open to prevent javascript: XSS
- Mask credential values in auth settings table (show last 4 chars only)
- Fix double-fetch auth using wrong property names (authToken/authUser → token/user)
- Wrap new URL() in try/catch to prevent crash on malformed source_url

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants