Guides
Security Best Practices

Security Best Practices

This guide covers security considerations for integrating with the Litmus API.

Authentication Security

API Key Management

  • Never commit API keys to version control
  • Use environment variables or secret management services
  • Rotate keys periodically
  • Use separate keys for development and production
# Good: Environment variable
export LITMUS_API_KEY="lk_abc123..."
 
# Bad: Hardcoded in source
api_key = "lk_abc123..."  # Don't do this!

Token Handling

  • Store tokens securely (httpOnly cookies for web apps)
  • Don't expose tokens in URLs or logs
  • Implement token refresh before expiration

Webhook Security

Always Verify Signatures

import hmac
import hashlib
 
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
🚫

Never skip signature verification! Without it, attackers can send fake webhook events to your server.

Use HTTPS

All webhook URLs must use HTTPS. We reject HTTP endpoints.

Validate Webhook Source

Optionally whitelist Litmus IP ranges (contact support for current list).

Data Security

Sensitive Data in Experiments

  • Don't include proprietary compound structures in hypothesis text
  • Use privacy settings (delayed_12mo or private) for sensitive work
  • Be aware that open experiments are publicly visible

Result Data

  • Results may contain sensitive measurements
  • Implement access controls in your systems
  • Consider data retention policies

Infrastructure Security

Network Security

# Restrict outbound connections
LITMUS_API_BASE = "https://api.litmus.science"
# Don't allow user-controlled URLs for API calls

Rate Limiting

Implement your own rate limiting to prevent runaway costs:

from functools import wraps
import time
 
def rate_limit(max_per_minute: int):
    calls = []
 
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()
            calls[:] = [c for c in calls if now - c < 60]
            if len(calls) >= max_per_minute:
                raise Exception("Rate limit exceeded")
            calls.append(now)
            return func(*args, **kwargs)
        return wrapper
    return decorator
 
@rate_limit(100)
def submit_experiment(spec):
    # ...

Compliance Considerations

Data Residency

  • API servers are located in the US
  • Contact support for data residency requirements

Audit Logging

The API logs all authenticated requests. Request audit logs via support.

HIPAA / PHI

Litmus does not support experiments involving protected health information (PHI) or human subjects research.

Reporting Security Issues

Report security vulnerabilities to security@litmus.science.

We operate a responsible disclosure program and will acknowledge reports within 48 hours.