| Version | Supported |
|---|---|
| 1.0.x | ✅ |
| < 1.0 | ❌ |
If you discover a security vulnerability in the ToggleCraft Ruby SDK, please report it to us privately.
DO NOT open a public GitHub issue for security vulnerabilities.
Send an email to: security@togglecraft.io
Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Acknowledgment: Within 48 hours
- Initial Assessment: Within 1 week
- Fix Timeline: Depends on severity
- Critical: 24-48 hours
- High: 1 week
- Medium: 2 weeks
- Low: Next release
We follow responsible disclosure practices:
- We'll acknowledge your report
- We'll investigate and develop a fix
- We'll release a security patch
- We'll publicly credit you (if desired)
❌ Never commit SDK keys to version control:
# DON'T DO THIS
client = ToggleCraft::Client.new(
sdk_key: 'tc_live_abc123...' # Hard-coded key
)✅ Use environment variables:
# DO THIS - Load from ENV
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY']
)✅ Use Rails encrypted credentials:
# DO THIS - Rails credentials (recommended)
client = ToggleCraft::Client.new(
sdk_key: Rails.application.credentials.togglecraft.sdk_key
)✅ Use dotenv gem for development:
# .env (add to .gitignore!)
TOGGLECRAFT_SDK_KEY=tc_dev_abc123...
# In your code
require 'dotenv/load'
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY']
)# Edit credentials
EDITOR=vim rails credentials:edit
# Add to credentials
togglecraft:
sdk_key: tc_live_abc123...
# Use in initializer
sdk_key: Rails.application.credentials.togglecraft.sdk_keyAlways use HTTPS in production:
# ✅ GOOD - HTTPS in production (default)
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY']
# Default URL is https://sse.togglecraft.io
)
# ⚠️ ONLY for local development
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
url: 'http://localhost:8080' # HTTP only for local dev
)By default, the SDK uses in-memory caching. For Redis caching, ensure Redis is secured:
# ✅ GOOD - Memory cache (default, secure)
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
cache_adapter: :memory
)
# ✅ GOOD - Redis with authentication
require 'redis'
redis = Redis.new(
url: ENV['REDIS_URL'],
ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_PEER }
)
client = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
cache_adapter: :redis,
redis: redis
)
# ❌ BAD - Unencrypted Redis without auth
redis = Redis.new(host: 'redis-server', port: 6379)The SDK is thread-safe and uses:
Concurrent::Mapfor flag storageConcurrent::AtomicBooleanfor state managementMutexfor listener operations
Safe for:
- Puma multi-threaded servers
- Sidekiq concurrent workers
- Any multi-threaded Ruby environment
Example - Safe Puma configuration:
# config/puma.rb
workers 4
threads 5, 5
# config/initializers/togglecraft.rb
Rails.application.config.togglecraft = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
share_connection: true # Share SSE across threads
)Important: SDK keys are visible to clients in browser environments (when using Rails with Turbo/Stimulus). Do not use server-side secrets or sensitive credentials as SDK keys.
- SDK keys should be scoped per environment (dev, staging, production)
- Rotate SDK keys if compromised
- Use separate keys for different applications if needed
Authentication is performed via HTTP header for the SSE connection:
X-SDK-Key: your-sdk-key
This header is transmitted over HTTPS, which encrypts it in transit.
When using Redis caching:
- Use TLS/SSL for Redis connections
- Enable Redis authentication (requirepass)
- Restrict Redis network access (bind to localhost or private network)
- Consider encrypting sensitive flag values before caching
# Secure Redis configuration
redis = Redis.new(
url: 'rediss://user:password@redis.example.com:6380/0', # rediss:// for TLS
ssl_params: {
verify_mode: OpenSSL::SSL::VERIFY_PEER,
ca_file: '/path/to/ca.pem'
}
)The SDK has minimal dependencies to reduce attack surface:
Runtime Dependencies:
concurrent-ruby(~> 1.2) - Thread-safe data structureshttp(~> 5.0) - HTTP clientsemantic(~> 1.6) - Semantic versioning
Development Dependencies:
rspec(~> 3.12)webmock(~> 3.19)simplecov(~> 0.22)
We actively monitor dependencies for security vulnerabilities using:
bundle audit(automated in CI)- GitHub Dependabot alerts
- Manual security reviews
# Install bundler-audit
gem install bundler-audit
# Update vulnerability database
bundle audit --update
# Check for vulnerabilities
bundle auditSecurity patches are released as soon as possible after verification:
- Critical vulnerabilities: Immediate patch release (1.x.y → 1.x.y+1)
- High vulnerabilities: Within 1 week
- Medium/Low vulnerabilities: Next minor release
Subscribe to releases on GitHub to receive security update notifications.
This SDK follows secure development practices:
- No eval() or instance_eval() - No dynamic code execution
- Input validation - All user inputs are validated
- Thread-safe operations - Uses concurrent-ruby primitives
- Minimal dependencies - Reduces supply chain attack risk
- Automated security scanning - bundle audit runs on every PR
- Comprehensive tests - 214+ tests with 62%+ coverage
Before deploying to production:
- SDK key stored in environment variables or Rails credentials
- HTTPS enforced for all connections
- Redis secured with authentication and TLS (if using Redis cache)
- Dependencies audited with
bundle audit - Logs don't expose SDK keys or sensitive data
- Error handling configured to avoid exposing internal details
- Connection pooling enabled for multi-process environments
-
at_exithook configured to clean up connections
❌ Don't log SDK keys:
# BAD - Logs SDK key
logger.info "Connecting with key: #{sdk_key}"✅ Log safely:
# GOOD - Mask SDK key
masked_key = "#{sdk_key[0..10]}***"
logger.info "Connecting with key: #{masked_key}"
# GOOD - Don't log key at all
logger.info "Connecting to ToggleCraft"The SDK's debug mode does not log SDK keys - it only logs connection state and flag updates.
# In controllers - don't pass params directly
def create
context = {
user: {
id: current_user.id, # Use authenticated user
email: current_user.email # Don't trust params
}
}
if togglecraft.enabled?('feature', context)
# ...
end
end
# DON'T DO THIS - Vulnerable to injection
context = params[:context] # User can manipulate contextConsider rate-limiting flag evaluations for public endpoints:
# Use rack-attack or similar
class ApplicationController < ActionController::Base
before_action :rate_limit_flags, only: [:public_endpoint]
def rate_limit_flags
# Implement rate limiting
end
endIf exposing flags to JavaScript via Turbo/Stimulus, ensure CSP allows your domain:
# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |policy|
policy.connect_src :self, 'https://sse.togglecraft.io'
endFor security concerns, contact: security@togglecraft.io
For general support: support@togglecraft.io