Skip to content

fix(config): redact Feishu encryptKey in config snapshots#53414

Merged
fabianwilliams merged 1 commit intoopenclaw:mainfrom
coygeek:codex/cr-mbx-feishu-encryptkey-config-redaction-bypass
Mar 26, 2026
Merged

fix(config): redact Feishu encryptKey in config snapshots#53414
fabianwilliams merged 1 commit intoopenclaw:mainfrom
coygeek:codex/cr-mbx-feishu-encryptkey-config-redaction-bypass

Conversation

@coygeek
Copy link
Copy Markdown
Contributor

@coygeek coygeek commented Mar 24, 2026

Fix Summary

When Feishu is configured in webhook mode, channels.feishu.encryptKey survives config redaction and is returned in plaintext to any operator.read client via config.get. The leaked key is the sole authenticator for inbound Feishu webhooks, enabling an attacker to forge accepted webhook events that OpenClaw processes as legitimate Feishu messages.

Issue Linkage

Fixes #53412

Security Snapshot

  • CVSS v3.1: 9.1 (Critical)
  • CVSS v4.0: 8.5 (High)

Implementation Details

Files Changed

  • src/config/redact-snapshot.test.ts (+5/-1)
  • src/config/schema.hints.test.ts (+18/-0)
  • src/config/schema.hints.ts (+1/-0)
  • src/plugin-sdk/secret-input-schema.ts (+17/-10)

Technical Analysis

  1. Configure Feishu with connectionMode: "webhook" and a plaintext channels.feishu.encryptKey value.
  2. Pair a gateway client that holds only the operator.read scope.
  3. Call config.get. Observe that the response payload at config.channels.feishu.encryptKey contains the raw key value rather than __OPENCLAW_REDACTED__.
  4. Using the leaked key, compute sha256(timestamp + nonce + encryptKey + JSON.stringify(payload)) and send a forged webhook to the Feishu path (default /feishu/events) with correct x-lark-request-timestamp, x-lark-request-nonce, and x-lark-signature headers.
  5. The request passes isFeishuWebhookSignatureValid() and is dispatched via eventDispatcher.invoke(..., { needCheck: false }).
  6. OpenClaw processes the forged event through its normal im.message.receive_v1 handler.

Validation Evidence

  • Command: pnpm exec oxlint src/ && pnpm build && pnpm check && pnpm test
  • Status: passed (with pre-existing baseline failures)

Risk and Compatibility

non-breaking; no known regression impact

AI-Assisted Disclosure

  • AI-assisted: yes
  • Model: opencode/github-copilot/gpt-5.4

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 24, 2026

Greptile Summary

This PR closes a security gap where the Feishu encryptKey credential was not being redacted in config snapshots, using a defense-in-depth approach that adds both pattern-based and schema-based detection.

  • Pattern fix (schema.hints.ts): Adds /encrypt.?key/i to SENSITIVE_PATTERNS, so any config path ending in encryptKey or encrypt_key is caught by name, matching the same style as /api.?key/i.
  • Schema registry fix (secret-input-schema.ts): Converts buildSecretInputSchema() from a factory returning a new z.union(...) instance per call to a module-level singleton registered with the sensitive Zod registry. This is the correct approach because mapSensitivePaths uses reference equality (sensitive.has(currentSchema)) to detect registered schemas — returning the same registered instance on every call is required for schema-level detection to work. The isUnwrappable/unwrap() loop in mapSensitivePaths correctly unwraps .optional() wrappers added by callers before reaching the registered union.
  • Test coverage: The unit test for the registry path uses field names that don't match any SENSITIVE_PATTERNS rule, cleanly isolating the schema-based detection. The integration test adds encryptKey to the Feishu config block and asserts end-to-end redaction.
  • The fix applies globally to all plugins that use buildSecretInputSchema(), not just Feishu — confirmed by tracing the export chain through secret-input.tssecret-input-schema.ts.

Confidence Score: 5/5

  • Safe to merge — minimal, targeted security fix with correct implementation and solid test coverage at both the unit and integration levels.
  • Both redaction layers (pattern match and schema registry) are correctly implemented. The singleton refactor is the right design choice for registry-based detection. The Feishu config schema already typed encryptKey with buildSecretInputSchema(), so the registry fix lands exactly where it needs to. No regressions are expected; the change is strictly additive from a security posture perspective.
  • No files require special attention.

Reviews (1): Last reviewed commit: "fix(cr-mbx-feishu-encryptkey-config-reda..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@fabianwilliams fabianwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean companion to #53418 — covers the Feishu encryptKey gap.

What I like:

  • Added encrypt.?key to SENSITIVE_PATTERNS — catches encryptKey, encrypt_key, and similar variants across all config paths
  • buildSecretInputSchema now registers with the sensitive marker, so any plugin using it gets automatic redaction
  • New test confirms channels.feishu.encryptKey AND nested account variants (channels.feishu.accounts.default.encryptKey) are caught
  • The buildSecretInputSchema test proves the registry-based approach works for arbitrary nested schemas

Small, focused, well-tested. LGTM — approve.

@fabianwilliams fabianwilliams merged commit 8e285d1 into openclaw:main Mar 26, 2026
36 of 39 checks passed
pxnt pushed a commit to pxnt/openclaw that referenced this pull request Mar 27, 2026
godlin-gh pushed a commit to YouMindInc/openclaw that referenced this pull request Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Feishu encryptKey bypasses config redaction, enabling webhook forgery

2 participants