From fccc222bd71f257b5d43aa053d36f0e52b79aa7d Mon Sep 17 00:00:00 2001 From: AlexFucuson9 Date: Tue, 7 Jul 2026 12:00:25 +0700 Subject: [PATCH] fix(slack): warn when slack_tokens.json is group/world-readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OAuth multi-workspace token file contains plaintext bot tokens for all saved Slack workspaces. Unlike the Google Chat adapter which sets 0o600 when writing credentials, the Slack token file has no permission enforcement — a default umask 022 makes it world-readable. Fix: check file permissions on read and emit a warning log with remediation instructions if the file is group- or world-readable. --- plugins/platforms/slack/adapter.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/platforms/slack/adapter.py b/plugins/platforms/slack/adapter.py index 5c540e656a90..cd2024aaaf46 100644 --- a/plugins/platforms/slack/adapter.py +++ b/plugins/platforms/slack/adapter.py @@ -1623,6 +1623,19 @@ class SlackAdapter(BasePlatformAdapter): tokens_file = get_hermes_home() / "slack_tokens.json" if tokens_file.exists(): try: + # Warn if the token file is world- or group-readable — it + # contains plaintext bot tokens for all saved workspaces. + import stat as _stat + + mode = tokens_file.stat().st_mode + if mode & (_stat.S_IRGRP | _stat.S_IROTH): + logger.warning( + "[Slack] %s is group/world-readable (mode 0%o). " + "Run: chmod 600 %s", + tokens_file.name, + _stat.S_IMODE(mode), + tokens_file, + ) saved = json.loads(tokens_file.read_text(encoding="utf-8")) for team_id, entry in saved.items(): tok = entry.get("token", "") if isinstance(entry, dict) else ""