Commit Graph

5512 Commits

Author SHA1 Message Date
Aether AI 3967ece625 fix(security): OC-25 — Validate OAuth state parameter to prevent CSRF attacks (#16058)
* fix(security): validate OAuth state parameter to prevent CSRF attacks (OC-25)

The parseOAuthCallbackInput() function in the Chutes OAuth flow had two
critical bugs that completely defeated CSRF state validation:

1. State extracted from callback URL was never compared against the
   expected cryptographic nonce, allowing attacker-controlled state values
2. When URL parsing failed (bare authorization code input), the catch block
   fabricated a matching state using expectedState, making the caller's
   CSRF check always pass

## Attack Flow

1. Victim runs `openclaw login chutes --manual`
2. System generates cryptographic state: randomBytes(16).toString("hex")
3. Browser opens: https://api.chutes.ai/idp/authorize?state=abc123...
4. Attacker obtains their OWN OAuth authorization code (out of band)
5. Attacker tricks victim into pasting just "EVIL_CODE" (not full URL)
6. parseOAuthCallbackInput("EVIL_CODE", "abc123...") is called
7. new URL("EVIL_CODE") throws → catch block executes
8. catch returns { code: "EVIL_CODE", state: "abc123..." } ← FABRICATED
9. Caller checks: parsed.state !== state → "abc123..." !== "abc123..." → FALSE
10. CSRF check passes! System calls exchangeChutesCodeForTokens()
11. Attacker's code exchanged for access + refresh tokens
12. Victim's account linked to attacker's OAuth session

Fix:
- Add explicit state validation against expectedState before returning
- Remove state fabrication from catch block; always return error for
  non-URL input
- Add comprehensive unit tests for state validation

Remediated by Aether AI Agent security analysis.

* fix(security): harden chutes manual oauth state check (#16058) (thanks @aether-ai-agent)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 15:28:52 +01:00
seheepeak cb9a5e1cb9 feat(sandbox): separate bind mounts for browser containers (#16230)
* feat(sandbox): add separate browser.binds config for browser containers

Allow configuring bind mounts independently for browser containers via
sandbox.browser.binds. When set, browser containers use browser-specific
binds instead of inheriting docker.binds. Falls back to docker.binds
when browser.binds is not configured for backwards compatibility.

Closes #14614

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

* fix(sandbox): honor empty browser binds override (#16230) (thanks @seheepeak)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 15:27:41 +01:00
Peter Steinberger 493f6f458b perf(test): speed up browser test suites 2026-02-14 14:25:54 +00:00
Peter Steinberger 57f40a5da6 perf(test): speed up config tests 2026-02-14 14:25:54 +00:00
shadril238 788ea6e9d1 fix: suppress false duplicate plugin id warning for symlinked extensions
When the same plugin directory is discovered through different path
representations (e.g. symlinks), the manifest registry incorrectly
warns about a duplicate plugin id. This is a false positive that
appears for bundled extensions like feishu (#16208).

Compare fs.realpathSync() of both candidates' rootDir before emitting
the duplicate warning. If they resolve to the same physical directory,
silently skip the duplicate instead of warning.

Also change seenIds from Set<string> to Map<string, PluginCandidate>
to track the first-seen candidate for comparison.

Closes #16208
2026-02-14 15:25:51 +01:00
Peter Steinberger 1a7e180e68 refactor(media): normalize inbound MediaType/MediaTypes defaults (#16233)
* refactor(media): normalize inbound media type defaults

* test(browser): fix Windows path expectation in file chooser hook
2026-02-14 15:18:19 +01:00
Peter Steinberger 00a0890889 fix(media): bound input media payload sizes 2026-02-14 15:16:06 +01:00
Peter Steinberger 4b1cadaecb refactor(media): normalize inbound media type defaults (#16228) 2026-02-14 15:06:13 +01:00
Peter Steinberger 35c0e66ed0 fix(security): harden hooks module loading 2026-02-14 15:03:27 +01:00
Peter Steinberger 3d0a41b584 test(gateway): isolate device identity in auth e2e 2026-02-14 14:57:19 +01:00
jasonftl 8025e7c6c2 fix(discord): respect gateway TLS config in exec approvals handler (#16216) (thanks @jasonftl) 2026-02-14 14:53:38 +01:00
Peter Steinberger 842499d6c5 test(security): reject hook archives with traversal entries (#16224) 2026-02-14 14:53:33 +01:00
Peter Steinberger 3aa94afcfd fix(security): harden archive extraction (#16203)
* fix(browser): confine upload paths for file chooser

* fix(browser): sanitize suggested download filenames

* chore(lint): avoid control regex in download sanitizer

* test(browser): cover absolute escape paths

* docs(browser): update upload example path

* refactor(browser): centralize upload path confinement

* fix(infra): harden tmp dir selection

* fix(security): harden archive extraction

* fix(infra): harden tar extraction filter
2026-02-14 14:42:08 +01:00
Peter Steinberger 7d3e5788e8 fix: stop enforcing <final> for ollama (#16191) (thanks @Glucksberg) 2026-02-14 14:21:34 +01:00
Glucksberg 74193ff754 fix(ollama): remove Ollama from isReasoningTagProvider (#2279)
Ollama's OpenAI-compatible endpoint handles reasoning natively via the
`reasoning` field in streaming chunks. Treating Ollama as a
reasoning-tag provider incorrectly forces <think>/<final> tag
enforcement, which causes stripBlockTags() to discard all output
(since Ollama models don't emit <final> tags), resulting in
'(no output)' for every Ollama model.

This fix removes 'ollama' from the isReasoningTagProvider() check,
allowing Ollama models to work correctly through the standard
content/reasoning field separation.
2026-02-14 14:21:34 +01:00
Tanwa Arpornthip c76288bdf1 fix(slack): download all files in multi-image messages (#15447)
* fix(slack): download all files in multi-image messages

resolveSlackMedia() previously returned after downloading the first
file, causing multi-image Slack messages to lose all but the first
attachment. This changes the function to collect all successfully
downloaded files into an array, matching the pattern already used by
Telegram, Line, Discord, and iMessage adapters.

The prepare handler now populates MediaPaths, MediaUrls, and
MediaTypes arrays so downstream media processing (vision, sandbox
staging, media notes) works correctly with multiple attachments.

Fixes #11892, #7536

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

* fix(slack): preserve MediaTypes index alignment with MediaPaths/MediaUrls

The filter(Boolean) on MediaTypes removed entries with undefined contentType,
shrinking the array and breaking index correlation with MediaPaths and MediaUrls.
Downstream code (media-note.ts, attachments.ts) requires these arrays to have
equal lengths for correct per-attachment MIME type lookup. Replace filter(Boolean)
with a nullish coalescing fallback to "application/octet-stream".

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

* fix(slack): align MediaType fallback and tests (#15447) (thanks @CommanderCrowCode)

* fix: unblock plugin-sdk account-id typing (#15447)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 14:16:02 +01:00
Peter Steinberger ef70a55b7a refactor(reply): clarify explicit reply tags in off mode (#16189)
* refactor(reply): clarify explicit reply tags in off mode

* fix(plugin-sdk): alias account-id subpath for extensions
2026-02-14 14:15:37 +01:00
Peter Steinberger 6f7d31c426 fix(security): harden plugin/hook npm installs 2026-02-14 14:07:14 +01:00
Peter Steinberger ec399aaddf perf(test): parallelize unit-isolated 2026-02-14 13:01:02 +00:00
Peter Steinberger 18e8bd68c5 fix(security): block hook manifest path escapes 2026-02-14 14:00:37 +01:00
Peter Steinberger 3bbd29bef9 perf(gateway): cache session list transcript fields 2026-02-14 12:52:51 +00:00
Peter Steinberger a0361b8ba9 fix(security): restrict hook transform module loading 2026-02-14 13:46:09 +01:00
Peter Steinberger 6543ce717c perf(test): avoid plugin-sdk barrel imports 2026-02-14 12:42:19 +00:00
Peter Steinberger 1ba266a8e8 refactor: split minimax-cn provider 2026-02-14 13:37:47 +01:00
Peter Steinberger bf080c2338 Merge remote-tracking branch 'origin/main' 2026-02-14 13:36:18 +01:00
Tak Hoffman 274da72c38 Revert "fix: don't auto-create HEARTBEAT.md on workspace init (openclaw#12027) thanks @shadril238" (#16183)
This reverts commit 386bb0c618.
2026-02-14 06:33:14 -06:00
Peter Steinberger 83248f7603 Merge remote-tracking branch 'origin/main' 2026-02-14 13:30:22 +01:00
Peter Steinberger af50b914a4 refactor(browser): centralize http auth 2026-02-14 13:30:11 +01:00
Peter Steinberger a2b45e1c13 fix(gateway): relax http tool deny typing 2026-02-14 13:30:05 +01:00
Aldo 7b39543e8d fix(reply): honour explicit [[reply_to_*]] tags when replyToMode is off (#16174)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 778fc2559ade85a37209866c2edbe33bfc5bbb86
Co-authored-by: aldoeliacim <17973757+aldoeliacim@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-14 13:29:42 +01:00
Peter Steinberger 0af76f5f0e refactor(gateway): centralize node.invoke param sanitization 2026-02-14 13:27:45 +01:00
Peter Steinberger c15946274e fix(gateway): allowlist system.run params 2026-02-14 13:27:45 +01:00
Peter Steinberger a7af646fdf fix(gateway): bind approval ids to device identity 2026-02-14 13:27:45 +01:00
Peter Steinberger 318379cdba fix(gateway): bind system.run approvals to exec approvals 2026-02-14 13:27:45 +01:00
Peter Steinberger 233483d2b9 refactor(security): centralize dangerous tool lists 2026-02-14 13:27:05 +01:00
Peter Steinberger 0cfea46293 fix: wire minimax-api-key-cn onboarding (#15191) (thanks @liuy) 2026-02-14 13:25:54 +01:00
Liu Yuan 9bb099736b feat: add minimax-api-key-cn option for China API endpoint
- Add 'minimax-api-key-cn' auth choice for Chinese users
- Reuse existing --minimax-api-key CLI option
- Use MINIMAX_CN_API_BASE_URL (https://api.minimaxi.com/anthropic)
- Similar to how moonshot supports moonshot-api-key-cn

Tested: build , check , test 
2026-02-14 13:25:54 +01:00
Peter Steinberger cd84885a4a test(browser): cover bridge auth registry fallback 2026-02-14 13:23:24 +01:00
Peter Steinberger 586176730c perf(gateway): optimize sessions/ws/routing 2026-02-14 12:21:44 +00:00
Peter Steinberger c90b3e4d5e perf(cli): speed up startup 2026-02-14 12:21:44 +00:00
Peter Steinberger a7a08b6650 test(gateway): cover tools allow/deny precedence 2026-02-14 13:18:49 +01:00
Peter Steinberger 153a7644ea fix(acp): tighten safe kind inference 2026-02-14 13:18:49 +01:00
Peter Steinberger 6dd6bce997 fix(security): enforce sandbox bridge auth 2026-02-14 13:17:41 +01:00
Peter Steinberger eb4215d570 perf(test): speed up Vitest bootstrap 2026-02-14 12:13:27 +00:00
Nicholas f8ba8f7699 fix(docs): update outdated hooks documentation URLs (#16165)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 8ed13fb02fae2cb6dd3cacdb3cd1ef37a5cdd4d8
Co-authored-by: nicholascyh <188132635+nicholascyh@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-14 13:05:37 +01:00
Peter Steinberger 4711a943e3 fix(browser): authenticate sandbox browser bridge server 2026-02-14 12:54:16 +01:00
Peter Steinberger bb1c3dfe10 fix(acp): prompt for non-read/search permissions 2026-02-14 12:53:27 +01:00
Peter Steinberger 539689a2f2 feat(security): warn when gateway.tools.allow re-enables dangerous HTTP tools 2026-02-14 12:48:02 +01:00
Peter Steinberger 3b56a6252b chore!: remove moltbot legacy state/config support 2026-02-14 12:40:47 +01:00
Nick Taylor 1fb52b4d7b feat(gateway): add trusted-proxy auth mode (#15940)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 279d4b304f83186fda44dfe63a729406a835dafa
Co-authored-by: nickytonline <833231+nickytonline@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-14 12:32:17 +01:00