Skip to content

Security: ToggleCraft/ruby-sdk

Security

SECURITY.md

Security Policy

Supported Versions

Version Supported
1.0.x
< 1.0

Reporting a Vulnerability

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.

How to Report

Send an email to: security@togglecraft.io

Include:

  • Description of the vulnerability
  • Steps to reproduce
  • Potential impact
  • Suggested fix (if any)

Response Timeline

  • 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

Responsible Disclosure

We follow responsible disclosure practices:

  1. We'll acknowledge your report
  2. We'll investigate and develop a fix
  3. We'll release a security patch
  4. We'll publicly credit you (if desired)

Security Best Practices

SDK Key Management

❌ 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']
)

Rails Credentials Setup

# 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_key

HTTPS

Always 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
)

Secure Cache Storage

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)

Thread Safety

The SDK is thread-safe and uses:

  • Concurrent::Map for flag storage
  • Concurrent::AtomicBoolean for state management
  • Mutex for 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
)

Known Limitations

Client-Side SDK Keys

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

SSE Authentication

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.

Redis Cache Security

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'
  }
)

Dependency Security

The SDK has minimal dependencies to reduce attack surface:

Runtime Dependencies:

  • concurrent-ruby (~> 1.2) - Thread-safe data structures
  • http (~> 5.0) - HTTP client
  • semantic (~> 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

Running Security Audits

# Install bundler-audit
gem install bundler-audit

# Update vulnerability database
bundle audit --update

# Check for vulnerabilities
bundle audit

Security Updates

Security patches are released as soon as possible after verification:

  1. Critical vulnerabilities: Immediate patch release (1.x.y → 1.x.y+1)
  2. High vulnerabilities: Within 1 week
  3. Medium/Low vulnerabilities: Next minor release

Subscribe to releases on GitHub to receive security update notifications.

Secure Development Practices

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

Production Checklist

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_exit hook configured to clean up connections

Logging Security

❌ 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.

Rails-Specific Security

Protect from Mass Assignment

# 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 context

Rate Limiting

Consider 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
end

Content Security Policy

If 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'
end

Contact

For security concerns, contact: security@togglecraft.io

For general support: support@togglecraft.io

There aren’t any published security advisories