This placeholder config allows Android CI builds to compile without
real Firebase credentials. For production builds, replace with actual
google-services.json from Firebase Console.
FCM push notifications will not work with this placeholder config.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix formatting in session-utils.store.ts
- Regenerate Swift protocol files with TOO_MANY_REQUESTS error code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add transferBatchState() method to EmbeddingService to preserve failure
tracking when the service is recreated during reindex operations
- Update manager.createEmbeddingService() to transfer state by default
- Skip state transfer when switching to fallback provider (fresh start)
- Add mock rateLimiter to send.test.ts to fix test failures
- Add error handling in audit-log.ts for ENOENT during test cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
chat.inject is a privileged operation that injects assistant messages into
transcripts. The injection sanitization was being called but its result was
ignored - the original message was used anyway.
Rather than using the sanitized text (which would be identical since
useBoundaries=false for assistant content), remove the sanitization entirely
because:
1. This injects assistant content, not user input - boundary markers are inappropriate
2. Injection patterns detect user prompt manipulations, not assistant responses
3. This is a privileged gateway operation requiring authenticated access
This addresses the new finding in the post-fix audit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix all 7 issues identified in the ChatGPT audit of transformation work:
1. Android build break: Remove duplicate normalizeMainKey/isCanonicalMainSessionKey
from NodeGatewaySync.kt (they're already in SessionKey.kt). Align both Android
and iOS implementations to use "main" as canonical (case-insensitive match).
2. Rate limiting: Wire rateLimiter through GatewayRequestContext and enforce:
- Auth failure backoff (recordAuthFailure on auth failure, clearAuthFailure on success)
- Request rate limiting before handleGatewayRequest
- Channel message rate limiting in send handler
- Add TOO_MANY_REQUESTS error code
3. Injection defenses: Call sanitizeIncomingMessage in chat.send and chat.inject
handlers to detect prompt injection attempts.
4. RBAC enforcement: Add canAccessAgent check in chat.send handler and
canExecuteCommand check in node-host runner for exec commands.
5. WhatsApp encrypted backup restore: Update maybeRestoreCredsFromBackup to
handle encrypted backup files (.bak.enc -> .json.enc restoration).
6. Exec blocklist bypass: Add evaluateBlocklist check in argv-only code path
in runner.ts (previously only checked for rawCommand path).
7. iOS voice transcript: Fix line 329 in NodeAppModel.swift to use computed
'key' variable instead of original 'sessionKey' parameter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unnecessary escape character in exec-blocklist regex
- Fix header spread in clawdhub client to handle all HeadersInit types
- Remove unused InjectionSeverity import from chat-sanitize test
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create a unified error module (src/errors/index.ts) that provides:
- ClawdbotError: Base error class with code and metadata support
- Common utilities: getErrorMessage, getErrorCode, getErrorStatus,
formatErrorForLog, formatErrorForUser, wrapError
- Type guards: isClawdbotError, isError
- Re-exports of domain-specific errors for discoverability
Domain errors remain co-located with their modules for cohesion.
This index provides a single discovery point without creating coupling.
Part of Phase 2: Architecture Cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract cohesive functionality from session-utils.ts (644 LOC) into
focused submodules while maintaining full backwards compatibility:
- session-utils.avatar.ts: Avatar resolution (data URIs, files, URLs)
- session-utils.agents.ts: Agent listing and discovery
- session-utils.store.ts: Store resolution and loading
The main session-utils.ts now orchestrates and re-exports all functions
preserving the existing public API. Core session listing functions
(deriveSessionTitle, loadSessionEntry, classifySessionKey, etc.) remain
in the main file.
Part of Phase 2: Architecture Cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security Documentation:
- docs/security/threat-model.md: Comprehensive threat model covering
channels, tools, gateway, local files, browser automation, and plugins
- docs/security/data-handling.md: Data handling policy covering storage,
retention, user rights (access, export, delete), and compliance
Doctor Security Check:
- Added credential encryption check to doctor-security.ts
- Warns about unencrypted WhatsApp/Web credentials
This completes Phase 1 Security Hardening (Tasks 1.1-1.6).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pairing Store Hardening:
- Increased pairing code length from 8 to 16 chars (80-bit entropy)
- Added HMAC-SHA256 signatures for store integrity verification
- Added rate limiting (10 attempts/minute per channel)
- Store is automatically reset if signature verification fails
- New ApproveChannelPairingCodeResult type includes rateLimited case
Exec Approval Nonces (Replay Protection):
- Added one-time-use nonces for approval socket requests
- Nonces are generated with 32 bytes of entropy (base64url encoded)
- Nonces expire after 5 minutes with automatic cleanup
- Responses must include matching nonce to be accepted
- Exported functions for testing: generateApprovalNonce, verifyAndConsumeNonce, isNonceValid
Tests:
- 11 pairing store tests (6 new security tests)
- 38 exec-approvals tests (8 new nonce tests)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Support macOS Keychain via `security` command
- Support Linux Secret Service via `secret-tool` (libsecret)
- Fallback to AES-256-GCM encrypted files with PBKDF2 key derivation
- Machine-derived encryption key for file fallback
- Utilities: generateSecureToken, hashSecret, verifySecretHash
- Migration helpers for moving plain-text credentials to secure storage
- Comprehensive test suite (27 tests)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tiered blocklist (critical/high/medium) for dangerous commands
- Block: rm -rf /, dd to disk, mkfs, halt/reboot, fork bombs, etc.
- Block: sudo, passwd, visudo, iptables, user management
- Warn but allow: command substitution, eval, curl POST, chmod 777
- Integrate blocklist into evaluateShellAllowlist (checked before allowlist)
- Add comprehensive test suite (47 tests)
- Export blocklist utilities for use by other modules
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds `messages` config option to session-memory hook (default: 15).
Fixes filter order bug - now filters user/assistant messages first,
then slices to get exactly N messages. Previously sliced first which
could result in fewer messages when non-message entries were present.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new dmScope option that includes accountId in session keys,
enabling isolated sessions per channel account for multi-bot setups.
- Add 'per-account-channel-peer' to DmScope type
- Update session key generation to include accountId
- Pass accountId through routing chain
- Add tests for new routing behavior (13/13 passing)
Closes#3094
Co-authored-by: Sebastian Almeida <89653954+SebastianAlmeida@users.noreply.github.com>
The MiniMax provider config was updated to use api.minimax.chat
instead of api.minimax.io in PR #3064, but the test expectation
was not updated.
🤖 Generated with Claude Code
- Re-export DirectoryConfigParams and ChannelDirectoryEntry from channels/targets
- Remove unused ChannelDirectoryEntry and resolveDiscordAccount imports
- Fix parseDiscordTarget calls to not pass incompatible options type
- Fix unused catch parameter
Fixes CI build failures on main.
🤖 Generated with Claude Code
Regular Telegram groups (without Topics/Forums enabled) can send
message_thread_id when users reply to messages. This was incorrectly
being used to create separate session keys like '-123:topic:42',
causing each reply chain to get its own conversation context.
Now resolveTelegramForumThreadId only returns a thread ID when the
chat is actually a forum (is_forum=true). For regular groups, the
thread ID is ignored, ensuring all messages share the same session.
DMs continue to use messageThreadId for thread sessions as before.