Description
Summary
Two separate bugs prevent the Discord channel from working properly:
- Capabilities JSON schema mismatch – Discovery fails because of a wrong field name.
- Missing Discord signature validation – The interactions endpoint cannot be verified by Discord because the host never checks
X-Signature-Ed25519 and X-Signature-Timestamp.
Bug 1: Capabilities header field name mismatch
Location: channels-src/discord/discord.capabilities.json
The Discord capabilities file uses header_name for the credential location:
"location":{"type":"header","header_name":"Authorization","prefix":"Bot "}
CredentialLocationSchema in src/tools/wasm/capabilities_schema.rs expects name:
Header {
name: String,
#[serde(default)]
prefix: Option<String>,
},
Impact: ChannelCapabilitiesFile::from_bytes() fails during discovery, the channel is skipped, and "Discord (WASM)" never shows up in the onboarding wizard.
Workaround: Use name instead of header_name in discord.capabilities.json.
Bug 2: Discord signature validation not implemented
Location: src/channels/wasm/router.rs (or equivalent webhook handler)
According to Discord's "Preparing for Interactions" docs, the endpoint must:
- Return
200 with {"type":1} for valid PING requests.
- Validate
X-Signature-Ed25519 and X-Signature-Timestamp and return 401 for invalid signatures.
The docs state:
"If either of these are not complete, your Interactions Endpoint URL will not be validated."
"Discord will also perform automated, routine security checks against your endpoint, including purposefully sending you invalid signatures."
Current behavior: The host only performs generic webhook secret checks. There is no Discord-specific Ed25519 validation. All requests (including invalid signatures) receive 200 OK with the correct PONG body.
Impact: Discord’s verification fails with: "The specified interactions endpoint url could not be verified."
Expected behavior:
Before forwarding to the WASM channel, validate the Ed25519 signature using discord_public_key:
- If invalid → return
401 Unauthorized.
- If valid → forward to the WASM channel.
Environment
- IronClaw v0.5.0
- Discord channel from
channels-src/discord
- Cloudflare Tunnel for webhook endpoint
- PostgreSQL database
References
Proposed fix
Bug 2: Discord signature validation
Add host-side validation in the webhook path before calling the WASM channel. Rough steps:
-
Detect Discord webhooks – Treat requests to /webhook/discord or channels whose capabilities include require_signature_verification: true.
-
Load discord_public_key – Read from the secrets store, similar to discord_bot_token. If not configured, either:
- return 401 for all Discord requests, or
- log a warning and skip validation (weaker, but keeps current behavior).
-
Validate signature before WASM call – In webhook_handler (or equivalent), for Discord:
- Read
X-Signature-Ed25519 and X-Signature-Timestamp.
- Use the raw request body (bytes) and public key to verify:
signature = hex_decode(X-Signature-Ed25519)
message = X-Signature-Timestamp + body
verify(message, signature, public_key) (e.g. ed25519-dalek or tweetnacl).
- If invalid or missing headers → return 401.
- If valid → continue as now and call the WASM channel.
-
Dependencies – Add something like ed25519-dalek or tweetnacl for Ed25519 verification.
-
Setup wizard – Ensure discord_public_key is configured during onboarding (e.g. in setup.required_secrets or equivalent for Discord).
Pseudocode:
// In webhook_handler, before call_on_http_request:
if channel_name == "discord" {
if let Some(public_key) = state.router.get_discord_public_key().await {
let sig = headers.get("X-Signature-Ed25519").and_then(|v| v.to_str().ok());
let ts = headers.get("X-Signature-Timestamp").and_then(|v| v.to_str().ok());
match (sig, ts) {
(Some(s), Some(t)) => {
if !verify_discord_signature(public_key, t, &body, s) {
return (StatusCode::UNAUTHORIZED, Json(json!({"error": "invalid request signature"})));
}
}
_ => return (StatusCode::UNAUTHORIZED, Json(json!({"error": "missing signature headers"}))),
}
}
}
Description
Summary
Two separate bugs prevent the Discord channel from working properly:
X-Signature-Ed25519andX-Signature-Timestamp.Bug 1: Capabilities header field name mismatch
Location:
channels-src/discord/discord.capabilities.jsonThe Discord capabilities file uses
header_namefor the credential location:CredentialLocationSchemainsrc/tools/wasm/capabilities_schema.rsexpectsname:Impact:
ChannelCapabilitiesFile::from_bytes()fails during discovery, the channel is skipped, and "Discord (WASM)" never shows up in the onboarding wizard.Workaround: Use
nameinstead ofheader_nameindiscord.capabilities.json.Bug 2: Discord signature validation not implemented
Location:
src/channels/wasm/router.rs(or equivalent webhook handler)According to Discord's "Preparing for Interactions" docs, the endpoint must:
200with{"type":1}for valid PING requests.X-Signature-Ed25519andX-Signature-Timestampand return401for invalid signatures.The docs state:
Current behavior: The host only performs generic webhook secret checks. There is no Discord-specific Ed25519 validation. All requests (including invalid signatures) receive
200 OKwith the correct PONG body.Impact: Discord’s verification fails with: "The specified interactions endpoint url could not be verified."
Expected behavior:
Before forwarding to the WASM channel, validate the Ed25519 signature using
discord_public_key:401 Unauthorized.Environment
channels-src/discordReferences
discord_public_keyand host-side validation, but the router does not implement it.Proposed fix
Bug 2: Discord signature validation
Add host-side validation in the webhook path before calling the WASM channel. Rough steps:
Detect Discord webhooks – Treat requests to
/webhook/discordor channels whose capabilities includerequire_signature_verification: true.Load
discord_public_key– Read from the secrets store, similar todiscord_bot_token. If not configured, either:Validate signature before WASM call – In
webhook_handler(or equivalent), for Discord:X-Signature-Ed25519andX-Signature-Timestamp.signature = hex_decode(X-Signature-Ed25519)message = X-Signature-Timestamp + bodyverify(message, signature, public_key)(e.g.ed25519-dalekortweetnacl).Dependencies – Add something like
ed25519-dalekortweetnaclfor Ed25519 verification.Setup wizard – Ensure
discord_public_keyis configured during onboarding (e.g. insetup.required_secretsor equivalent for Discord).Pseudocode: