Severity Assessment
CVSS Assessment
| Metric |
v3.1 |
v4.0 |
| Score |
9.1 / 10.0 |
8.5 / 10.0 |
| Severity |
Critical |
High |
| Vector |
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L |
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:H/VA:L/SC:L/SI:H/SA:L |
| Calculator |
CVSS v3.1 Calculator |
CVSS v4.0 Calculator |
Threat Model Alignment
Classification: security-specific
The config redaction system is an explicit security boundary in OpenClaw: config.get returns a redacted snapshot specifically to prevent credential disclosure to read-scoped clients. This finding demonstrates that the Feishu encryptKey field escapes all three redaction layers (schema hints, sensitive patterns, and plugin SDK secret-input registration), leaking the sole webhook authenticator. This is not covered by the Out of Scope section — it is not a multi-tenant assumption, prompt injection, or operator-intended behavior. The encryptKey is a cryptographic secret used for webhook signature verification, and its exposure enables webhook forgery from outside the trust boundary.
Impact
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.
Affected Component
File: src/config/schema.hints.ts:104-110
const SENSITIVE_PATTERNS = [
/token$/i,
/password/i,
/secret/i,
/api.?key/i,
/serviceaccount(?:ref)?$/i,
];
File: extensions/feishu/src/config-schema.ts:197
encryptKey: buildSecretInputSchema().optional(),
File: extensions/feishu/src/monitor.transport.ts:51-76 (signature validation)
File: extensions/feishu/src/monitor.transport.ts:217-219 (needCheck: false dispatcher invocation)
File: src/gateway/method-scopes.ts:88 (config.get in READ_SCOPE)
Technical Reproduction
- Configure Feishu with
connectionMode: "webhook" and a plaintext channels.feishu.encryptKey value.
- Pair a gateway client that holds only the
operator.read scope.
- Call
config.get. Observe that the response payload at config.channels.feishu.encryptKey contains the raw key value rather than __OPENCLAW_REDACTED__.
- 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.
- The request passes
isFeishuWebhookSignatureValid() and is dispatched via eventDispatcher.invoke(..., { needCheck: false }).
- OpenClaw processes the forged event through its normal
im.message.receive_v1 handler.
Demonstrated Impact
The redaction bypass is caused by three compounding gaps:
-
Pattern miss: isSensitiveConfigPath in src/config/schema.hints.ts checks SENSITIVE_PATTERNS which match token$, password, secret, api.?key, and serviceaccount. The field name encryptKey matches none of these patterns.
-
Missing sensitive registry: buildSecretInputSchema() in src/plugin-sdk/secret-input-schema.ts returns a plain z.union(...) without registering the schema in the sensitive Zod registry (src/config/zod-schema.sensitive.ts). The mapSensitivePaths function in schema.hints.ts checks sensitive.has(currentSchema) when walking the schema tree, but since buildSecretInputSchema never calls sensitive.add(), the encryptKey field is not flagged through this path either.
-
Missing extension uiHints: buildChannelConfigSchema in src/channels/plugins/config-schema.ts produces only { schema: ... } with no uiHints property. The Feishu channel plugin at extensions/feishu/src/channel.ts:423 calls buildChannelConfigSchema(FeishuConfigSchema) without supplying per-field sensitivity annotations. As a result, applyChannelHints in src/config/schema.ts never adds a channels.feishu.encryptKey entry to the merged hints, and applySensitiveHints has no key to evaluate.
With the encryptKey leaked, the webhook authentication is fully compromised. isFeishuWebhookSignatureValid() in monitor.transport.ts:51-76 computes a SHA-256 HMAC using only timestamp + nonce + encryptKey + JSON.stringify(payload) and the verificationToken is not consulted in this path. The subsequent eventDispatcher.invoke(..., { needCheck: false }) at line 217-219 explicitly disables the Lark SDK's built-in request verification. The repository's own e2e test (monitor.webhook-e2e.test.ts:24-41) demonstrates that any correctly signed plaintext Feishu event envelope reaches the dispatcher.
Environment
Tested against openclaw/openclaw tag v2026.3.23-2 (commit 3b1657803292509f382fd6456242fb3e3d325461).
Prerequisites:
- Feishu configured in webhook mode with a plaintext
channels.feishu.encryptKey
- A gateway client holding
operator.read scope
- Knowledge of any valid Feishu chat the bot participates in
Remediation Advice
Register the Zod schema returned by buildSecretInputSchema() with the sensitive registry so that mapSensitivePaths marks all fields using that schema as sensitive. Alternatively, add /encrypt.?key/i to SENSITIVE_PATTERNS as a defense-in-depth fallback. Verify that config.get returns __OPENCLAW_REDACTED__ for channels.feishu.encryptKey (and per-account encryptKey fields) when called with operator.read scope, and add regression coverage for this redaction path.
Severity Assessment
CVSS Assessment
Threat Model Alignment
Classification:
security-specificThe config redaction system is an explicit security boundary in OpenClaw:
config.getreturns a redacted snapshot specifically to prevent credential disclosure to read-scoped clients. This finding demonstrates that the FeishuencryptKeyfield escapes all three redaction layers (schema hints, sensitive patterns, and plugin SDK secret-input registration), leaking the sole webhook authenticator. This is not covered by the Out of Scope section — it is not a multi-tenant assumption, prompt injection, or operator-intended behavior. TheencryptKeyis a cryptographic secret used for webhook signature verification, and its exposure enables webhook forgery from outside the trust boundary.Impact
When Feishu is configured in webhook mode,
channels.feishu.encryptKeysurvives config redaction and is returned in plaintext to anyoperator.readclient viaconfig.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.Affected Component
File:
src/config/schema.hints.ts:104-110File:
extensions/feishu/src/config-schema.ts:197File:
extensions/feishu/src/monitor.transport.ts:51-76(signature validation)File:
extensions/feishu/src/monitor.transport.ts:217-219(needCheck: falsedispatcher invocation)File:
src/gateway/method-scopes.ts:88(config.getinREAD_SCOPE)Technical Reproduction
connectionMode: "webhook"and a plaintextchannels.feishu.encryptKeyvalue.operator.readscope.config.get. Observe that the response payload atconfig.channels.feishu.encryptKeycontains the raw key value rather than__OPENCLAW_REDACTED__.sha256(timestamp + nonce + encryptKey + JSON.stringify(payload))and send a forged webhook to the Feishu path (default/feishu/events) with correctx-lark-request-timestamp,x-lark-request-nonce, andx-lark-signatureheaders.isFeishuWebhookSignatureValid()and is dispatched viaeventDispatcher.invoke(..., { needCheck: false }).im.message.receive_v1handler.Demonstrated Impact
The redaction bypass is caused by three compounding gaps:
Pattern miss:
isSensitiveConfigPathinsrc/config/schema.hints.tschecksSENSITIVE_PATTERNSwhich matchtoken$,password,secret,api.?key, andserviceaccount. The field nameencryptKeymatches none of these patterns.Missing sensitive registry:
buildSecretInputSchema()insrc/plugin-sdk/secret-input-schema.tsreturns a plainz.union(...)without registering the schema in thesensitiveZod registry (src/config/zod-schema.sensitive.ts). ThemapSensitivePathsfunction inschema.hints.tscheckssensitive.has(currentSchema)when walking the schema tree, but sincebuildSecretInputSchemanever callssensitive.add(), the encryptKey field is not flagged through this path either.Missing extension uiHints:
buildChannelConfigSchemainsrc/channels/plugins/config-schema.tsproduces only{ schema: ... }with nouiHintsproperty. The Feishu channel plugin atextensions/feishu/src/channel.ts:423callsbuildChannelConfigSchema(FeishuConfigSchema)without supplying per-field sensitivity annotations. As a result,applyChannelHintsinsrc/config/schema.tsnever adds achannels.feishu.encryptKeyentry to the merged hints, andapplySensitiveHintshas no key to evaluate.With the encryptKey leaked, the webhook authentication is fully compromised.
isFeishuWebhookSignatureValid()inmonitor.transport.ts:51-76computes a SHA-256 HMAC using onlytimestamp + nonce + encryptKey + JSON.stringify(payload)and theverificationTokenis not consulted in this path. The subsequenteventDispatcher.invoke(..., { needCheck: false })at line 217-219 explicitly disables the Lark SDK's built-in request verification. The repository's own e2e test (monitor.webhook-e2e.test.ts:24-41) demonstrates that any correctly signed plaintext Feishu event envelope reaches the dispatcher.Environment
Tested against
openclaw/openclawtagv2026.3.23-2(commit3b1657803292509f382fd6456242fb3e3d325461).Prerequisites:
channels.feishu.encryptKeyoperator.readscopeRemediation Advice
Register the Zod schema returned by
buildSecretInputSchema()with thesensitiveregistry so thatmapSensitivePathsmarks all fields using that schema as sensitive. Alternatively, add/encrypt.?key/itoSENSITIVE_PATTERNSas a defense-in-depth fallback. Verify thatconfig.getreturns__OPENCLAW_REDACTED__forchannels.feishu.encryptKey(and per-accountencryptKeyfields) when called withoperator.readscope, and add regression coverage for this redaction path.