Severity: Low · Category: Credential-at-rest / hardening
Assessed at: main head 673a32d9699e869be910ed1caa3cef3aa87d94ce (read-only security health-check, 2026-07-29)
Summary
slack_cli is well-hardened overall — GitHub Actions are SHA-pinned with least-privilege permissions: contents: read (resolving closed #24/#25/#26), and no secrets are committed (.env.example is an empty template, .env is gitignored). The items below are Low-severity hardening opportunities in local credential handling; filing one consolidated issue rather than several.
Findings (all Low, confirmed)
- Plaintext token storage. OAuth access token (
xoxp-…) and Socket Mode app token (xapp-…) are written unencrypted to ~/.dart_slack/:
lib/src/auth/credentials_store.dart:37-40
lib/src/auth/app_config_store.dart:47-51
Standard for CLIs but no OS-keychain integration.
- File permissions applied after write (TOCTOU) and not on Windows.
_setFilePermissions() runs chmod 600 only on macOS/Linux and only after the file is created with the default umask:
lib/src/auth/credentials_store.dart:59-63, lib/src/auth/app_config_store.dart:68-72, lib/src/auth/oauth_flow.dart:174-179 (TLS key/cert).
Brief world/group-readable window; on Windows no restriction is applied.
- Bearer token forwarded to API-supplied URLs without host validation.
lib/src/slack_api/slack_api_client.dart:307-313 attaches Authorization: Bearer to whatever url_private_download URL the API returned; lib/src/socket_mode/socket_mode_client.dart:690 connects to the API-supplied WS URL. Low (relies on authenticated TLS Slack responses).
Minor (informational): command_runner.dart:1026-1028 prints full stack traces to stderr on parse errors (gate behind --verbose); credentials_store.dart:17-19 interpolates HOME without the resilient fallback used by AppConfigStore; .gitignore ignores pubspec.lock (commit it for reproducible builds of an executable package).
Remediation
- Create credential/key files atomically with mode 0600 (temp-file + rename) and apply an equivalent ACL on Windows.
- Optionally integrate an OS keyring (Keychain / libsecret / Windows Credential Manager).
- Validate API-returned URL hosts against a Slack-domain allowlist before attaching the bearer token.
Severity: Low · Category: Credential-at-rest / hardening
Assessed at:
mainhead673a32d9699e869be910ed1caa3cef3aa87d94ce(read-only security health-check, 2026-07-29)Summary
slack_cliis well-hardened overall — GitHub Actions are SHA-pinned with least-privilegepermissions: contents: read(resolving closed #24/#25/#26), and no secrets are committed (.env.exampleis an empty template,.envis gitignored). The items below are Low-severity hardening opportunities in local credential handling; filing one consolidated issue rather than several.Findings (all Low, confirmed)
xoxp-…) and Socket Mode app token (xapp-…) are written unencrypted to~/.dart_slack/:lib/src/auth/credentials_store.dart:37-40lib/src/auth/app_config_store.dart:47-51Standard for CLIs but no OS-keychain integration.
_setFilePermissions()runschmod 600only on macOS/Linux and only after the file is created with the default umask:lib/src/auth/credentials_store.dart:59-63,lib/src/auth/app_config_store.dart:68-72,lib/src/auth/oauth_flow.dart:174-179(TLS key/cert).Brief world/group-readable window; on Windows no restriction is applied.
lib/src/slack_api/slack_api_client.dart:307-313attachesAuthorization: Bearerto whateverurl_private_downloadURL the API returned;lib/src/socket_mode/socket_mode_client.dart:690connects to the API-supplied WS URL. Low (relies on authenticated TLS Slack responses).Minor (informational):
command_runner.dart:1026-1028prints full stack traces to stderr on parse errors (gate behind--verbose);credentials_store.dart:17-19interpolatesHOMEwithout the resilient fallback used byAppConfigStore;.gitignoreignorespubspec.lock(commit it for reproducible builds of an executable package).Remediation