Skip to content

feat: Add HMAC-SHA256 webhook signature validation for Slack#588

Merged
nickpismenkov merged 3 commits intomainfrom
feat/hmac-sha256
Mar 6, 2026
Merged

feat: Add HMAC-SHA256 webhook signature validation for Slack#588
nickpismenkov merged 3 commits intomainfrom
feat/hmac-sha256

Conversation

@nickpismenkov
Copy link
Copy Markdown
Contributor

No description provided.

@github-actions github-actions bot added scope: channel/wasm WASM channel runtime scope: extensions Extension management scope: dependencies Dependency updates size: XL 500+ changed lines labels Mar 6, 2026
@nickpismenkov nickpismenkov linked an issue Mar 6, 2026 that may be closed by this pull request
@github-actions github-actions bot added risk: medium Business logic, config, or moderate-risk modules contributor: regular 2-5 merged PRs labels Mar 6, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the security posture for Slack webhooks by introducing HMAC-SHA256 signature validation. This mechanism ensures that all incoming Slack webhook requests are legitimate and have not been tampered with, by verifying their cryptographic signature against a pre-configured secret. The implementation is flexible, allowing secrets to be defined per channel via capabilities, and is thoroughly tested to handle various validation scenarios.

Highlights

  • HMAC-SHA256 Signature Validation for Slack: Implemented HMAC-SHA256 signature validation for incoming Slack webhooks, enhancing security by verifying the authenticity and integrity of requests.
  • Configurable via Channel Capabilities: Introduced a new webhook.hmac_secret_name field in slack.capabilities.json to specify the secret used for HMAC validation, allowing per-channel configuration.
  • Core Logic and Integration: Added core HMAC-SHA256 verification logic, including timestamp staleness checks, and integrated it into the webhook processing pipeline, rejecting unauthorized or tampered requests.
  • Router and Manager Updates: Updated the WasmChannelRouter to manage HMAC secrets and the ExtensionManager to load and register these secrets from the secrets store during channel activation and refresh.
  • Comprehensive Testing: Included extensive unit and integration tests to cover various scenarios for HMAC signature validation, ensuring robustness against missing headers, invalid signatures, tampered bodies, and stale timestamps.
Changelog
  • Cargo.lock
    • Added hmac crate dependency.
  • Cargo.toml
    • Added hmac crate dependency at version 0.12.
  • channels-src/slack/slack.capabilities.json
    • Added webhook.hmac_secret_name field to specify the Slack signing secret.
  • src/channels/wasm/loader.rs
    • Added hmac_secret_name method to LoadedChannel to retrieve the HMAC secret name from capabilities.
  • src/channels/wasm/router.rs
    • Added hmac_secrets field to WasmChannelRouter to store HMAC signing secrets.
    • Initialized hmac_secrets in the WasmChannelRouter::new constructor.
    • Ensured hmac_secrets are removed when a channel is unregistered.
    • Added register_hmac_secret and get_hmac_secret methods for managing HMAC secrets.
    • Integrated HMAC-SHA256 signature verification into the webhook_handler function.
    • Added new test cases for HMAC secret management and webhook validation scenarios.
  • src/channels/wasm/schema.rs
    • Added hmac_secret_name field to WebhookSchema for configuring Slack signing secrets.
    • Added hmac_secret_name getter method to ChannelCapabilitiesFile.
  • src/channels/wasm/signature.rs
    • Updated module documentation to include Slack HMAC-SHA256 verification.
    • Added verify_slack_signature function to perform HMAC-SHA256 validation with timestamp checks.
    • Added comprehensive unit tests for verify_slack_signature covering valid, invalid, tampered, and stale signatures.
  • src/extensions/manager.rs
    • Retrieved hmac_secret_name during channel loading.
    • Registered HMAC signing secrets with the WasmChannelRouter during channel activation if specified.
    • Refreshed HMAC signing secrets in the router when channel capabilities are reloaded.
  • src/main.rs
    • Retrieved hmac_secret_name during initial WASM channel setup.
    • Registered HMAC signing secrets with the WasmChannelRouter during initial channel setup if specified.
Activity
  • No specific activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces HMAC-SHA256 signature validation for Slack webhooks, enhancing security. The changes include adding the hmac dependency, updating channel capabilities to specify the signing secret, and implementing the verification logic in the WASM channel router. The implementation is well-tested. My review includes one suggestion to refactor duplicated code in src/extensions/manager.rs for improved performance and maintainability.

Note: Security Review is unavailable for this PR.

Comment thread src/extensions/manager.rs Outdated
@nickpismenkov nickpismenkov added the contributor: core 20+ merged PRs label Mar 6, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds HMAC-SHA256 webhook signature validation for Slack channels, complementing the existing Ed25519 signature verification for Discord. The implementation follows Slack's documented signing protocol (v0 versioned HMAC-SHA256 with timestamp-based replay protection) and integrates it consistently into the existing WASM channel webhook routing infrastructure.

Changes:

  • Added verify_slack_signature function with HMAC-SHA256 computation, staleness checking, and constant-time comparison, alongside comprehensive unit tests.
  • Extended the WASM channel router, schema, loader, and capabilities to support declaring and registering HMAC signing secrets (hmac_secret_name) for channels.
  • Refactored the refresh_active_channel method in ExtensionManager to load the capabilities file once instead of reading it from disk multiple times.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/channels/wasm/signature.rs Added verify_slack_signature function and extensive test coverage for HMAC-SHA256 verification
src/channels/wasm/router.rs Added hmac_secrets field, register/get methods, unregister cleanup, webhook handler HMAC verification block, and integration tests
src/channels/wasm/schema.rs Added hmac_secret_name field to WebhookSchema and accessor on ChannelCapabilitiesFile
src/channels/wasm/loader.rs Added hmac_secret_name() accessor on LoadedChannel
src/main.rs Register HMAC secret during channel setup if declared in capabilities
src/extensions/manager.rs Register/refresh HMAC secret during hot-activation and refresh flows; refactored capabilities file loading to a single read
channels-src/slack/slack.capabilities.json Declared hmac_secret_name: "slack_signing_secret" in Slack's webhook config
Cargo.toml / Cargo.lock Added explicit hmac = "0.12" dependency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +640 to +642

assert!(
!verify_slack_signature(signing_secret, "-1", body, "v0=abc123", 0),
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This test doesn't actually verify that negative timestamps are rejected. With now_secs = 0 and timestamp = "-1", the staleness check passes because (0 - (-1)).abs() = 1 ≤ 300. The test only passes because the signature "v0=abc123" doesn't match the computed HMAC — not because the negative timestamp was detected.

Compare with the analogous Discord test at line 387, which uses now_secs = TEST_TS = 1234567890, making the staleness check properly reject the -1 timestamp.

To properly test negative timestamp rejection, either use a now_secs value far from -1 (similar to the Discord test), or add explicit negative-timestamp rejection logic in verify_slack_signature.

Suggested change
assert!(
!verify_slack_signature(signing_secret, "-1", body, "v0=abc123", 0),
let timestamp = "-1";
// Use a correctly signed message so that the failure is due to the timestamp,
// not because the signature is invalid.
let signature = sign_slack_message(signing_secret, timestamp, body);
assert!(
!verify_slack_signature(signing_secret, timestamp, body, &signature, SLACK_TEST_TS),

Copilot uses AI. Check for mistakes.
Comment on lines +161 to +167
pub fn hmac_secret_name(&self) -> Option<&str> {
self.capabilities
.channel
.as_ref()
.and_then(|c| c.webhook.as_ref())
.and_then(|w| w.hmac_secret_name.as_deref())
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The existing schema tests include thorough coverage for the signature_key_secret_name field (see test_webhook_schema_signature_key_secret_name, test_signature_key_secret_name_none_when_missing, and test_discord_capabilities_signature_key at lines 738-783). There are no corresponding tests for the new hmac_secret_name field. Consider adding:

  1. A test that parses hmac_secret_name from capabilities JSON and verifies the accessor returns the expected value.
  2. A test that verifies hmac_secret_name returns None when the field is absent.
  3. A test that verifies the actual slack.capabilities.json declares hmac_secret_name: "slack_signing_secret" (similar to test_discord_capabilities_signature_key on line 774).

Copilot uses AI. Check for mistakes.
@nickpismenkov nickpismenkov merged commit 14de4c1 into main Mar 6, 2026
19 checks passed
@nickpismenkov nickpismenkov deleted the feat/hmac-sha256 branch March 6, 2026 03:27
This was referenced Mar 6, 2026
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
)

* feat: Add HMAC-SHA256 webhook signature validation for Slack

* review fixes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: regular 2-5 merged PRs risk: medium Business logic, config, or moderate-risk modules scope: channel/wasm WASM channel runtime scope: dependencies Dependency updates scope: extensions Extension management size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add HMAC-SHA256 webhook signature validation for Slack

3 participants