Welcome message files in the data/ directory use the following naming pattern:
message-<team_id>-<channel_id>-ephemeral.md
<team_id>: The Slack team (workspace) ID (e.g.,T070JPE5BQQ)<channel_id>: The Slack channel ID (e.g.,C06V9S85YR1)
Examples:
message-T070JPE5BQQ-C06V9S85YR1-ephemeral.mdβ Ephemeral join message for teamT070JPE5BQQin channelC06V9S85YR1message-T070JPE5BQQ-C06V9S85YR1.mdβ Persistent/channel template fallback for the same team/channel
Backward compatibility:
ephemeral-T070JPE5BQQ-C06V9S85YR1.mdis still recognized by the worker.
This convention makes it easy to distinguish between ephemeral and persistent messages and to target specific workspaces and channels.
An intelligent Slack bot for the OWASP community
π¬ Join OWASP Slack Β· π Report Bug Β· β¨ Request Feature
BLT-Lettuce is an intelligent Slack bot designed for the OWASP Slack workspace. It welcomes new members, helps them discover projects, and connects the global security community.
Note: This Slack bot functionality has been incorporated into the main BLT repository and is being transferred back to this repo for better organization.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OWASP Slack Workspace β
βββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cloudflare Worker (Python) β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββ β
β β Webhook β β Stats β β Project Discovery β β
β β Handler β β Tracking β β Flowchart β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββ β
βΌ βΌ βΌ
β Cloudflare β β GitHub API β β GitHub Pages β
β KV Storage β β (Org scanning) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
The bot uses a conversational flowchart to help users find OWASP projects:
βββββββββββββββββββββββββββββββββββββββ
β User Initiates Chat β
βββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββ
β "What type of project interests β
β you?" (Multiple Choice) β
β β’ Documentation/Standards β
β β’ Security Tools β
β β’ Deliberately Insecure Apps β
β β’ Research/Education β
βββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββ
β "What technology stack?" β
β β’ Python β’ Java β’ JavaScript β
β β’ Go β’ .NET β’ Any β
βββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββ
β Query cached project metadata β
β from configured GitHub orgs β
βββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββ
β Return matching project links β
β with descriptions and stats β
βββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββ
β No matches? Offer to: β
β β’ Start over with different params β
β β’ Learn how to start a new project β
βββββββββββββββββββββββββββββββββββββββ
View real-time statistics at our Stats Page:
- π Members welcomed
- β‘ Commands executed
- π GitHub project health metrics
- π Global availability status
BLT-Lettuce is now fully powered by a Cloudflare Python Worker (src/worker.py) that serves as the complete backend:
- Homepage: Serves the stats at the root URL
- Slack Events: Handles all webhook events (team joins, messages, mentions)
- Welcome Messages: Sends personalized welcome messages to new members
- Message Handling: Detects keywords like "contribute" and provides helpful responses
- Direct Messages: Responds to user DMs
- Stats Tracking: Tracks statistics in KV storage with atomic updates
- Stats API: Provides a JSON endpoint for live statistics
- Multi-Org Support: Can be installed in any Slack organization
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Homepage |
/webhook |
POST | Slack webhook for events |
/stats |
GET | Returns statistics JSON |
/health |
GET | Health check endpoint |
- Go to Slack API and create a new app or use the
manifest.yaml - If creating manually:
- Enable Event Subscriptions and add the webhook URL:
https://your-worker.workers.dev/webhook - Subscribe to these bot events:
team_join,message.channels,message.im,app_mention - Enable Interactivity and set Request URL to:
https://your-worker.workers.dev/webhook
- Enable Event Subscriptions and add the webhook URL:
- Install the app to your workspace
- Copy the Bot User OAuth Token and use it for
SLACK_TOKEN - Copy the Signing Secret and use it for
SIGNING_SECRET
chat:write- Send messagesim:write- Open DM conversationsim:read- Read direct messagesim:history- Read DM historychannels:history- Read channel messageschannels:read- View basic channel informationusers:read- Read user informationteam:read- Read workspace information
Required
SLACK_TOKEN- Bot User OAuth Token (xoxb-...)SIGNING_SECRET- Slack App Signing Secret
Optional Channel Configuration
For multi-organization deployments, you can configure custom channel IDs:
JOINS_CHANNEL_ID- Channel ID where join notifications are posted (optional)CONTRIBUTE_ID- Channel ID for contribution guidelines link (optional)DEPLOYS_CHANNEL- Channel name for deployment notifications (optional)
Note: If these are not set, the bot will skip channel-specific features (like posting join notifications to a monitoring channel) but all core functionality (welcome DMs, keyword detection) will still work.
To find a channel ID in Slack:
- Right-click on the channel name β "Copy link"
- The ID is the last part:
https://workspace.slack.com/archives/C06RMMRMGHE
Stats are stored in Cloudflare KV and include:
joins: Number of new team members who have joinedcommands: Number of commands runlast_updated: Timestamp of last update
Stats are workspace-specific and use optimistic locking to handle concurrent updates.
- All Slack requests are verified using HMAC signature validation
- Replay attacks are prevented with timestamp checking (5-minute window)
- The bot ignores its own messages to prevent loops
- Error messages are sanitized to avoid exposing internal details
- Wrangler CLI for Cloudflare Workers
- Cloudflare account
- Slack Bot Token and Signing Secret
-
Clone the repository
git clone https://github.com/OWASP-BLT/BLT-Lettuce.git cd BLT-Lettuce -
Install Wrangler and login
npm install -g wrangler wrangler login
-
Set up secrets
wrangler secret put SLACK_TOKEN # Your Bot User OAuth Token wrangler secret put SIGNING_SECRET # Your Signing Secret
Or use the automated setup script (recommended for production):
# Copy the example env file cp .env.production.example .env.production # Edit with your production credentials nano .env.production # Run the setup script python scripts/setup-env.py
See Environment Setup Guide for detailed instructions.
-
Deploy the worker
wrangler deploy
-
Configure Slack App
- Use the
manifest.yamlto create or update your Slack app - Or manually configure Event Subscriptions URL:
https://your-worker.workers.dev/webhook - Subscribe to events:
team_join,message.channels,message.im,app_mention
- Use the
This bot supports org-wide deployment and can be installed in any Slack workspace:
- Create your Slack app using the provided
manifest.yaml - Deploy the Cloudflare Worker to your account
- Enable Org-Wide App Installation in your Slack app settings
- Share the installation URL with other organizations
Each organization will have its own isolated statistics and configuration.
BLT-Lettuce/
βββ src/
β βββ worker.py # Complete Python worker with all bot logic
β βββ lettuce/ # Bot plugins and modules (for reference)
βββ wrangler.toml # Worker configuration
βββ manifest.yaml # Slack App manifest for easy setup
βββ docs/
β βββ index.html # GitHub Pages stats (reference)
βββ app.py # Legacy Flask application (kept for reference)
βββ data/
β βββ projects.json # OWASP project metadata cache
β βββ repos.json # Repository categorization
βββ tests/ # Test suite
βββ pyproject.toml # Python dependencies
βββ README.md # This file
Note: The primary application is now the Cloudflare Worker in src/worker.py. The Flask app (app.py) and related plugins are kept for historical reference and may be removed in a future release. All new development should focus on the Cloudflare Worker implementation.
We welcome contributions from everyone! Here's how to get started:
- Fork the Repository - Click "Fork" at the top right of this page
- Clone Your Fork
git clone https://github.com/YOUR-USERNAME/BLT-Lettuce.git
- Create a Branch
git checkout -b feature/your-feature-name
- Make Changes - Follow our coding standards (enforced by pre-commit hooks)
- Test Your Changes
poetry run pytest
- Commit with Conventional Commits
git commit -m "feat: add new feature" - Push and Open a PR
git push origin feature/your-feature-name
Watch our contribution walkthrough video for a step-by-step guide.
poetry run pytestpoetry run ruff check --fix .
poetry run ruff format .pip install pre-commit
pre-commit installThis section contains the complete deployment guide previously kept in DEPLOYMENT.md.
Before you begin, make sure you have:
- A Cloudflare account (free tier works)
- A Slack workspace where you have admin permissions
- Node.js and npm installed (for Wrangler CLI)
npm install -g wranglerwrangler loginThis will open a browser window for you to authenticate.
Edit wrangler.toml and replace the placeholder database_id with your actual D1 database ID.
- Go to https://api.slack.com/apps
- Click Create New App -> From an app manifest
- Select your workspace
- Copy the contents of manifest.yaml from this repo
- Paste it and click Create
- Update the Request URLs in the manifest with your actual worker URL:
- Change https://your-worker.workers.dev/webhook to your actual URL
- You will get this URL after deploying in Step 3
- Go to https://api.slack.com/apps
- Click Create New App -> From scratch
- Name it "BLT-Lettuce" and select your workspace
- Configure OAuth and Permissions:
- Add these Bot Token Scopes:
- chat:write
- im:write
- im:read
- im:history
- channels:history
- channels:read
- users:read
- team:read
- Add these Bot Token Scopes:
- Enable Event Subscriptions:
- Set Request URL to https://your-worker.workers.dev/webhook
- Subscribe to bot events:
- team_join
- message.channels
- message.im
- message.mpim
- app_mention
- Enable Interactivity:
- Go to OAuth and Permissions
- Install the app to your workspace
- Copy the Bot User OAuth Token (starts with xoxb-)
- Go to Basic Information
- Copy the Signing Secret
# Set your Slack Bot Token
wrangler secret put SLACK_TOKEN
# Set your Signing Secret
wrangler secret put SIGNING_SECRET# Channel where join notifications are posted
wrangler secret put JOINS_CHANNEL_ID
# Channel ID for contribution guidelines
wrangler secret put CONTRIBUTE_IDTo find a channel ID in Slack:
- Right-click on the channel name
- Select Copy link
- The ID is the last part of the URL, for example: https://workspace.slack.com/archives/C06RMMRMGHE
wrangler deployYou will get a URL like: https://blt-lettuce-worker.your-subdomain.workers.dev
If you created your app before deploying:
- Go back to your Slack app settings
- Update these URLs with your actual worker URL:
- Event Subscriptions -> Request URL: https://your-actual-worker-url.workers.dev/webhook
- Interactivity and Shortcuts -> Request URL: https://your-actual-worker-url.workers.dev/webhook
- Click Save Changes
Slack will verify the URL and you should see a green checkmark when configured correctly.
- In your Slack workspace, invite a test user or create a new account
- The bot should automatically send them a welcome DM
- Try sending a message with the word "contribute" and the bot should respond
- Visit your worker URL in a browser to see the homepage
To allow other Slack workspaces to install your bot:
- In your Slack app settings, go to Manage Distribution
- Remove hard-coded information, if any
- Enable Org-Wide App Installation
- Share your app install link
Each organization will have its own isolated data in the Cloudflare D1 database.
- Make sure the worker is deployed: wrangler deploy
- Check that the URL in Slack matches exactly: https://your-worker.workers.dev/webhook
- Look at worker logs: wrangler tail
- Check that secrets are set: wrangler secret list
- Verify the bot has the right permissions in Slack
- Check logs: wrangler tail
- Make sure the bot is installed in your workspace
- Make sure the bot has im:write permission
- Verify the bot is installed in the workspace
- Some users may have DMs disabled in their settings
wrangler tailVisit https://your-worker-url.workers.dev/ to see the full homepage with:
- Live statistics
- Bot features
- GitHub project information
To update your worker after making changes:
wrangler deployThe update is instant with no downtime required.
Cloudflare Workers free tier includes:
- 100,000 requests per day
- 10ms CPU time per request
For a typical Slack workspace, this is usually sufficient.
If you encounter issues:
- Check the GitHub issues in this repository
- Review the Cloudflare Workers documentation
- Check the Slack API documentation
- Never commit your secrets (SLACK_TOKEN, SIGNING_SECRET) to version control
- The worker verifies all requests from Slack using HMAC signature validation
- Replay attacks are prevented with timestamp validation
- All secrets are stored securely in Cloudflare encrypted storage
This project is licensed under the AGPL-3.0 License - see the LICENSE file for details.
- OWASP Foundation for supporting open-source security
- All our amazing contributors
- The OWASP Slack community for feedback and ideas
Made with π by the OWASP BLT Team