Skip to content

security(clawrouter): require configurable owner for /wallet and /stats; set /stats requireAuth true#22

Closed
hubofvalley wants to merge 283 commits intoBlockRunAI:mainfrom
hubofvalley:main
Closed

security(clawrouter): require configurable owner for /wallet and /stats; set /stats requireAuth true#22
hubofvalley wants to merge 283 commits intoBlockRunAI:mainfrom
hubofvalley:main

Conversation

@hubofvalley
Copy link

@hubofvalley hubofvalley commented Feb 13, 2026

Summary of Changes:

Dynamic Owner List: Added isAllowedUser() and resolveAllowedUsers() to handle configurable owner IDs.
Improved Security: /stats now requires authentication (requireAuth: true) and both /stats and /wallet now enforce the owner check.
Flexible Matching: Supports both exact IDs (e.g., 123) and platform-prefixed IDs (e.g., telegram:123).
Secure Default: If no users are configured, sensitive commands return a clear configuration error instead of potentially exposing data.
How to use: Set the allowed users via environment variable or plugin config:

export CLAWROUTER_ALLOWED_USERS="telegram:123,whatsapp:456"
Or add allowedUsers: ["telegram:123"] to your OpenClaw plugin configuration.

1bcMax and others added 30 commits February 4, 2026 11:48
Ambiguous cases now default to MEDIUM tier instead of calling
Gemini Flash for classification. Eliminates the extra API call
(200-400ms + x402 payment) for ~20% of routed requests.

Routing is now fully local: 14-dimension weighted scoring in <1ms,
zero external API calls. Configurable via ambiguousDefaultTier.
- Fix: when pre-auth payment is rejected without x-payment-required
  header, retry clean (no payment header) to get proper 402 flow
- Fix: minimum estimated amount floor of $0.0001 to avoid zero-amount
  payment rejections
- Add: e2e test suite covering health, non-streaming, streaming,
  smart routing, dedup, and error paths. All 7 tests pass.
… build

- Add ESLint with typescript-eslint for linting src/
- Add Prettier for consistent code formatting
- Add CI workflow: format check → lint → typecheck → build (Node 20)
- Fix 6 existing lint errors (unused imports, prefer-const)
- Format all source files with Prettier
- Add Kimi K2.5 to routing examples (agentic swarm use case)
- Add Moonshot to providers list (now 6 providers)
- Add Kimi K2.5 to models table ($0.60/M input, $3.00/M output)
- Add dedicated section explaining Kimi K2.5 strengths:
  - Agent swarm (100 parallel agents, 4.5x faster)
  - Extended tool chains (200-300 calls without drift)
  - Vision-to-code (UI mockups to React)
  - 76% cheaper than Claude Opus on agentic benchmarks
- Update architecture diagram to include Moonshot
- claude-opus-4.5: $15/$75 → $5/$25
- kimi-k2.5: $0.6/$2.5 → $0.5/$2.4 (correct OpenRouter price)
…et errors

- Add BalanceMonitor class with RPC-based USDC balance checking on Base
- Add InsufficientFundsError and EmptyWalletError typed error classes
- Add pre-request balance check before payment
- Add onLowBalance and onInsufficientFunds callbacks
- Add startup balance check with warnings
- Add optimistic cache deduction after successful payments
- Add cache invalidation on payment failure

Thresholds:
- Low balance warning: < $1.00
- Empty wallet error: < $0.0001

Tests: 28 tests passing (16 unit, 5 integration, 7 e2e)
- Add 180s request timeout (configurable via requestTimeoutMs)
- Add client disconnect cleanup to prevent memory leaks
- Add RpcError class for distinguishing RPC failures from empty wallets
- Create retry.ts with exponential backoff for 429/502/503/504
- Enhance /health endpoint with ?full=true for balance info
- Add 19 retry tests and 4 RpcError tests

51 tests passing (20 balance + 19 retry + 7 e2e + 5 integration)
Users were confused because the README troubleshooting section
documents port 8402, but the proxy was using random ports by default.

This change:
- Sets DEFAULT_PORT = 8402 constant
- Changes default from port 0 (random) to 8402
- Adds JSDoc for port option documenting the default

Now 'curl http://localhost:8402/health' works as documented.
The old 'openclaw config set model' command doesn't exist.
Updated to show correct methods:
- Edit ~/.openclaw/openclaw.json with agents.defaults.model.primary
- Or use /model command in conversation
1bcMax and others added 8 commits February 13, 2026 16:58
- Add logging to loadSavedWallet() to detect read failures
- Add post-write verification in generateAndSaveWallet()
- Distinguish between ENOENT (expected) and other read errors
- Throw error if wallet file write verification fails
- Add test/manual-wallet-test.sh for manual testing
- Add test/test-wallet-persistence.ts for automated testing

This fixes the issue where wallets were regenerating on gateway restart
due to silent failures in file read/write operations.
Fixes:
- Multiple transactions per prompt due to "Request too large" errors
- 200KB API limit blocking agentic workloads (200-225KB contexts)

Features:
- Auto-compression: Requests >180KB are automatically compressed
- Conservative compression config (whitespace + deduplication + JSON compact)
- Tool call safety: Preserves tool IDs, function names, and arguments
- Pre-request size validation: Rejects oversized requests BEFORE payment
- Request size error patterns: Prevents wasted fallback attempts

Implementation:
- Ported BlockRun's LLM-safe context compression library (7 layers)
- Added compression to proxy.ts after routing, before dedup
- Added ProxyOptions: autoCompressRequests, compressionThresholdKB, maxRequestSizeKB
- Added PROVIDER_ERROR_PATTERNS for size errors
- Comprehensive tests: 13/13 passed (compression, tool call safety, size validation)

Dual Compression Strategy:
- Client-side (ClawRouter): 210KB → ~200KB (enables passing API limit)
- Server-side (BlockRun): 200KB → ~140KB (reduces token charges)
- Result: Users can send larger contexts + pay less per request

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@1bcMax
Copy link
Member

1bcMax commented Feb 14, 2026

Thanks for the security improvement! The direction is right, but I have some concerns before merging:

1. Breaking Change Without Migration Path

This will immediately block all existing users who haven't configured CLAWROUTER_ALLOWED_USERS. Users upgrading will find /stats and /wallet suddenly broken with no warning.

Suggestion: Consider backwards compatibility - either allow unrestricted access when no users are configured (with a deprecation warning), or make this an opt-in feature.

2. Does /stats Need This Level of Protection?

  • /wallet export exposes private keys → must protect
  • /stats is read-only usage data → does it need the same protection?

Consider tiered protection: strict for /wallet, optional for /stats.

3. Bare ID Matching Security Concern

// If "123" is in allowedUsers, it matches ALL platforms:
"telegram:123" 
"whatsapp:123"   // Could be a different person!

Different platforms may have overlapping user IDs. This could be a security hole.

Suggestion: Remove bare ID matching, require full platform-prefixed IDs only.

4. Code Duplication

The owner guard logic is duplicated in both commands. Consider extracting to a helper function.


Happy to discuss further or review a revised version!

1bcMax and others added 19 commits February 13, 2026 22:09
When models return 413 Payload Too Large (e.g., request exceeds context limit),
ClawRouter now correctly retries with the next model instead of failing immediately.
Remove Windows-specific documentation and test infrastructure:
- docs/windows-installation.md
- test/test-model-selection.ps1
- test/run-docker-test-windows.ps1
- test/Dockerfile.windows
- .github/workflows/test-windows.yml
- Windows section from README.md
…BlockRunAI#25)

The previous implementation chained waiters by patching entry.resolve
via closures. This was fragile and hard to reason about.

More critically, removeInflight() (called on client disconnect or
request error) deleted the inflight entry without resolving pending
waiters — causing them to hang forever with no response.

Changes:
- Replace closure-chain pattern with a simple resolvers array
- On complete(): iterate all resolvers and resolve each one
- On removeInflight(): resolve waiters with 503 error instead of
  leaving them hanging, so clients can retry independently

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…design

- Remove price comparison focus
- Add 6 concrete pain points from OpenClaw GitHub issues
- Emphasize agent-native architecture (wallet vs API key)
- Add x402 flow diagram
- Simplify migration section
Removes artificial 200KB limit on request sizes. Compression still
optimizes large requests, but no hard limit is enforced. Let upstream
API handle size constraints if needed.

Changes:
- Remove maxRequestSizeKB option from ProxyOptions
- Remove 413 size validation logic in proxy
- Update compression tests to expect large requests to succeed
- Update docs to reflect compression is for optimization, not limits
Fixes 400 Unknown model error when users specify models like
blockrun/anthropic/claude-sonnet-4 instead of anthropic/claude-sonnet-4.

The resolveModelAlias function now strips the blockrun/ prefix for ALL
models, not just when looking up aliases.
ClawRouter now automatically truncates conversation history to stay under
BlockRun's 200 message limit. Keeps all system messages and the most
recent conversation messages.

This prevents '400 Too many messages' errors for long conversations.
- SIMPLE tier primary: nvidia/kimi-k2.5 → moonshot/kimi-k2.5 (/bin/zsh.50/.40)
- ecoTiers SIMPLE primary: nvidia/kimi-k2.5 → moonshot/kimi-k2.5
- ecoTiers MEDIUM fallback: nvidia/kimi-k2.5 → moonshot/kimi-k2.5

Direct moonshot routing is more reliable than nvidia's hosted version.
- SIMPLE: moonshot/kimi-k2.5 (coding)
- MEDIUM: claude-sonnet-4 (reasoning/instructions)
- COMPLEX: claude-opus-4.5 (architecture/audits)
- REASONING: claude-sonnet-4 (reasoning)

Removed GPT models from premium tier per user feedback.
…lockRunAI#28)

blockrun/sonnet, blockrun/opus, and blockrun/haiku were registered with
aliases "sonnet", "opus", and "haiku" which shadow the core Anthropic
model aliases. This caused `primary: "sonnet"` to route through blockrun
instead of the local Claude CLI backend.

Rename to br-sonnet, br-opus, br-haiku so the core aliases resolve to
anthropic/ models as expected. Users can still access blockrun-proxied
Anthropic models via blockrun/sonnet or /model br-sonnet.

Also update alias injection to fix stale aliases in existing configs.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Replace openai-codex/gpt-5.3-codex with openai/gpt-5.2-codex (available now)
- Update codex alias to point to gpt-5.2-codex
- Claude Opus 4.6 already configured as primary for premium tier
- Update agentic tier fallbacks to use Opus 4.6
- Moonshot Kimi K2.5 already configured

All three models now aligned with BlockRun backend catalog.
- Format MEDIUM fallback array (multi-line)
- Format COMPLEX fallback array (multi-line)
- Format REASONING fallback array (multi-line)

Resolves GitHub Actions CI formatting check failure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <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.

7 participants