Skip to content

fix: defer SignatureVerifier construction so Socket Mode apps init without a signing secret#1541

Merged
zimeg merged 5 commits into
mainfrom
fix-1535-socket-mode-empty-signing-secret
Jun 30, 2026
Merged

fix: defer SignatureVerifier construction so Socket Mode apps init without a signing secret#1541
zimeg merged 5 commits into
mainfrom
fix-1535-socket-mode-empty-signing-secret

Conversation

@zimeg

@zimeg zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

This pull request fixes a regression where a Socket Mode app fails to initialize with ValueError: signing_secret must not be empty. when running on slack_sdk>=3.43.0.

  • slack_sdk 3.43.0 made SignatureVerifier.signing_secret a validated property whose setter rejects an empty/whitespace secret on construction (it was a plain, unvalidated attribute in 3.42.0).
  • App.__init__ eagerly builds the RequestVerification middleware — and therefore a SignatureVerifier — for every app, including Socket Mode apps that legitimately have no signing secret, so initialization now blows up.
  • Fix: construct the SignatureVerifier lazily on first use. Request verification is already skipped for Socket Mode requests (_can_skip), so the verifier is never built for them; the once-per-app construction is memoized.
  • HTTP-mode behavior is unchanged: a valid signing secret is still required, and an empty secret still fails when a request actually needs verifying (preserving fix: Require signatures for ssl_check request verification #1495).
  • AsyncRequestVerification inherits this __init__, so both sync and async paths are covered by the single change.

Fixes #1535

Testing

This is an init-time regression that only reproduces against slack_sdk>=3.43.0 (the version range bolt-python already allows; CI may resolve an earlier patch). To reproduce and verify manually:

  1. In a fresh environment, install this branch alongside slack_sdk==3.43.0.
  2. Before the fix, constructing a Socket Mode app raises the error:
    from slack_bolt import App
    App(token="xoxb-...", token_verification_enabled=False)  # raises ValueError: signing_secret must not be empty.
  3. With the fix, the same construction succeeds, and an actual Socket Mode app started with SocketModeHandler connects and handles events normally.
  4. Confirm HTTP mode is unaffected: an HTTP app with a valid signing secret still verifies request signatures, and requests with an invalid/missing signature are still rejected with 401.

Category

  • slack_bolt.App and/or its core components
  • slack_bolt.async_app.AsyncApp and/or its core components
  • Adapters in slack_bolt.adapter
  • Document pages under /docs
  • Others

Requirements

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run ./scripts/install_all_and_run_tests.sh after making the changes.

…thout a signing secret

slack_sdk>=3.43.0 validates the signing secret when a SignatureVerifier is
constructed, raising "ValueError: signing_secret must not be empty." App.__init__
eagerly builds the RequestVerification middleware (and thus a SignatureVerifier)
for every app, including Socket Mode apps that have no signing secret, so those
apps now fail to initialize.

Construct the SignatureVerifier lazily on first use instead. Request verification
is already skipped for Socket Mode requests, so the verifier is never built for
them. HTTP requests still require a valid signing secret as before.

Fixes #1535

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.37%. Comparing base (29b9dbd) to head (2ae9fe6).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1541   +/-   ##
=======================================
  Coverage   91.37%   91.37%           
=======================================
  Files         228      228           
  Lines        7279     7285    +6     
=======================================
+ Hits         6651     6657    +6     
  Misses        628      628           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@zimeg zimeg self-assigned this Jun 30, 2026
@zimeg zimeg added this to the 1.29.0 milestone Jun 30, 2026
zimeg and others added 3 commits June 30, 2026 12:36
Add sync and async tests confirming that request verification still raises
for an HTTP request when the signing secret is empty, so the lazy verifier
cannot be weakened into silently accepting unverified requests. Drop the
now-redundant explanatory comments.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
@zimeg

zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

HTTP-mode verification — confirming the fix preserves the empty-secret guard

Tested the patched build in HTTP mode (socket_mode_enabled: false) with no SLACK_SIGNING_SECRET set. As intended, the request now reaches the middleware and the verifier raises lazily on first use — HTTP requests still require a non-empty signing secret (the behavior the new test_http_request_with_empty_signing_secret_raises tests lock in), so an unconfigured secret surfaces as a clear error rather than being silently accepted:

ValueError: signing_secret must not be empty.
127.0.0.1 - - [REDACTED] "POST /slack/events HTTP/1.1" 500 -
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.ssl_check.ssl_check.SslCheck
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.request_verification.request_verification.RequestVerification
ERROR:slack_bolt.App:Failed to run a middleware (error: signing_secret must not be empty.)
Traceback (most recent call last):
  File ".../slack_bolt/app/app.py", line 561, in dispatch
    resp = middleware.process(req=req, resp=resp, next=middleware_next)
  File ".../slack_bolt/middleware/request_verification/request_verification.py", line 51, in process
    if self.verifier.is_valid(body, timestamp, signature):
       ^^^^^^^^^^^^^
  File ".../slack_bolt/middleware/request_verification/request_verification.py", line 32, in verifier
    self._verifier = SignatureVerifier(signing_secret=self._signing_secret)
  File ".../slack_sdk/signature/__init__.py", line 29, in __init__
    self.signing_secret = signing_secret
  File ".../slack_sdk/signature/__init__.py", line 41, in signing_secret
    raise ValueError("signing_secret must not be empty.")

For Socket Mode (the original #1535 report), the verifier is never constructed and the app starts cleanly. ✅

@zimeg

zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

HTTP-mode verification — with SLACK_SIGNING_SECRET set

The complement to the previous comment: same HTTP setup, but with a valid signing secret configured. The full middleware chain applies cleanly and the verifier builds without error — no regression to HTTP request verification:

DEBUG:slack_bolt.App:Applying slack_bolt.middleware.ssl_check.ssl_check.SslCheck
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.request_verification.request_verification.RequestVerification
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.authorization.single_team_authorization.SingleTeamAuthorization
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.ignoring_self_events.ignoring_self_events.IgnoringSelfEvents
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.url_verification.url_verification.UrlVerification
DEBUG:slack_bolt.App:Applying slack_bolt.middleware.attaching_function_token.attaching_function_token.AttachingFunctionToken

@zimeg

zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

Socket Mode verification — the original #1535 case

Confirming Socket Mode (socket_mode_enabled: true) with no signing secret, on slack_sdk==3.43.0 — the exact reproduction from the issue. With the patch, the verifier is never constructed (request verification is skipped for Socket Mode), and the app starts and connects cleanly. No more ValueError: signing_secret must not be empty.

@WilliamBergamin WilliamBergamin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a minor comment on the comment but I think this is good to ship 💯 🚀

Comment thread slack_bolt/middleware/request_verification/request_verification.py Outdated
Comment on lines +76 to +81
def test_http_request_with_empty_signing_secret_raises(self):
middleware = RequestVerification(signing_secret="")
req = BoltRequest(body="payload={}", headers={})
resp = BoltResponse(status=404)
with pytest.raises(ValueError):
middleware.process(req=req, resp=resp, next=next)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice 💯

Comment on lines +68 to +74
def test_socket_mode_request_skips_verification_without_signing_secret(self):
middleware = RequestVerification(signing_secret="")
req = BoltRequest(mode="socket_mode", body="payload={}", headers={})
resp = BoltResponse(status=404, body="default")
resp = middleware.process(req=req, resp=resp, next=next)
assert resp.status == 200
assert resp.body == "next"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Praise 🚀

Co-authored-by: William Bergamin <wbergamin@salesforce.com>
@zimeg zimeg marked this pull request as ready for review June 30, 2026 20:04
@zimeg zimeg requested a review from a team as a code owner June 30, 2026 20:04
@zimeg

zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

@WilliamBergamin Immense thanks for the help getting this out - let's merge for a release🚢 💨

@zimeg zimeg merged commit 7fdd404 into main Jun 30, 2026
16 checks passed
@zimeg zimeg deleted the fix-1535-socket-mode-empty-signing-secret branch June 30, 2026 20:07
@zimeg

zimeg commented Jun 30, 2026

Copy link
Copy Markdown
Member Author

Fixes slackapi/python-slack-sdk#1903!

@msmygit

msmygit commented Jul 1, 2026

Copy link
Copy Markdown

@zimeg, is it now mandatory to pass in the 2nd argument token_verification_enabled=False without a signing_secret? Will self.app = App(token=SLACK_BOT_TOKEN) not work anymore?

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.

ValueError: signing_secret must not be empty.

3 participants