diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d00e7319..4eda32488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,11 @@ Docs: https://docs.clawd.bot -## 2026.1.25 - -### Changes -- TBD. +## 2026.1.24-3 ### Fixes - Gateway: harden reverse proxy handling for local-client detection and unauthenticated proxied connects. (#1795) Thanks @orlyjamie. +- Security audit: flag loopback Control UI with auth disabled as critical. (#1795) Thanks @orlyjamie. ## 2026.1.24-2 diff --git a/docs/platforms/mac/release.md b/docs/platforms/mac/release.md index 7f37951cb..d2d267661 100644 --- a/docs/platforms/mac/release.md +++ b/docs/platforms/mac/release.md @@ -30,17 +30,17 @@ Notes: # From repo root; set release IDs so Sparkle feed is enabled. # APP_BUILD must be numeric + monotonic for Sparkle compare. BUNDLE_ID=com.clawdbot.mac \ -APP_VERSION=2026.1.24-1 \ +APP_VERSION=2026.1.24-3 \ APP_BUILD="$(git rev-list --count HEAD)" \ BUILD_CONFIG=release \ SIGN_IDENTITY="Developer ID Application: ()" \ scripts/package-mac-app.sh # Zip for distribution (includes resource forks for Sparkle delta support) -ditto -c -k --sequesterRsrc --keepParent dist/Clawdbot.app dist/Clawdbot-2026.1.24-1.zip +ditto -c -k --sequesterRsrc --keepParent dist/Clawdbot.app dist/Clawdbot-2026.1.24-3.zip # Optional: also build a styled DMG for humans (drag to /Applications) -scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.24-1.dmg +scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.24-3.dmg # Recommended: build + notarize/staple zip + DMG # First, create a keychain profile once: @@ -48,26 +48,26 @@ scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.24-1.dmg # --apple-id "" --team-id "" --password "" NOTARIZE=1 NOTARYTOOL_PROFILE=clawdbot-notary \ BUNDLE_ID=com.clawdbot.mac \ -APP_VERSION=2026.1.24-1 \ +APP_VERSION=2026.1.24-3 \ APP_BUILD="$(git rev-list --count HEAD)" \ BUILD_CONFIG=release \ SIGN_IDENTITY="Developer ID Application: ()" \ scripts/package-mac-dist.sh # Optional: ship dSYM alongside the release -ditto -c -k --keepParent apps/macos/.build/release/Clawdbot.app.dSYM dist/Clawdbot-2026.1.24-1.dSYM.zip +ditto -c -k --keepParent apps/macos/.build/release/Clawdbot.app.dSYM dist/Clawdbot-2026.1.24-3.dSYM.zip ``` ## Appcast entry Use the release note generator so Sparkle renders formatted HTML notes: ```bash -SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.24-1.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml +SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.24-3.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml ``` Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/clawdbot/clawdbot/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry. Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing. ## Publish & verify -- Upload `Clawdbot-2026.1.24-1.zip` (and `Clawdbot-2026.1.24-1.dSYM.zip`) to the GitHub release for tag `v2026.1.24-1`. +- Upload `Clawdbot-2026.1.24-3.zip` (and `Clawdbot-2026.1.24-3.dSYM.zip`) to the GitHub release for tag `v2026.1.24-3`. - Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml`. - Sanity checks: - `curl -I https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml` returns 200. diff --git a/package.json b/package.json index 39e7b31d2..5d77e25d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clawdbot", - "version": "2026.1.24-2", + "version": "2026.1.24-3", "description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent", "type": "module", "main": "dist/index.js", diff --git a/src/security/audit.test.ts b/src/security/audit.test.ts index 0051b753f..2ee7e27ee 100644 --- a/src/security/audit.test.ts +++ b/src/security/audit.test.ts @@ -77,6 +77,31 @@ describe("security audit", () => { ); }); + it("flags loopback control UI without auth as critical", async () => { + const cfg: ClawdbotConfig = { + gateway: { + bind: "loopback", + controlUi: { enabled: true }, + auth: { mode: "none" as any }, + }, + }; + + const res = await runSecurityAudit({ + config: cfg, + includeFilesystem: false, + includeChannelSecurity: false, + }); + + expect(res.findings).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + checkId: "gateway.loopback_no_auth", + severity: "critical", + }), + ]), + ); + }); + it("flags logging.redactSensitive=off", async () => { const cfg: ClawdbotConfig = { logging: { redactSensitive: "off" }, diff --git a/src/security/audit.ts b/src/security/audit.ts index db51d576f..3695cf049 100644 --- a/src/security/audit.ts +++ b/src/security/audit.ts @@ -236,6 +236,18 @@ function collectGatewayConfigFindings(cfg: ClawdbotConfig): SecurityAuditFinding }); } + if (bind === "loopback" && controlUiEnabled && auth.mode === "none") { + findings.push({ + checkId: "gateway.loopback_no_auth", + severity: "critical", + title: "Gateway auth disabled on loopback", + detail: + "gateway.bind is loopback and gateway.auth is disabled. " + + "If the Control UI is exposed through a reverse proxy, unauthenticated access is possible.", + remediation: "Set gateway.auth (token recommended) or keep the Control UI local-only.", + }); + } + if (tailscaleMode === "funnel") { findings.push({ checkId: "gateway.tailscale_funnel",