Security Policy

Supported Versions

Version

Supported

0.1.x

Yes

Security Features

This package implements multiple security layers to protect against common email-based attacks.

1. Transport Security

TLS 1.2+ Enforcement

All IMAP and SMTP connections require TLS 1.2 or higher:

context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_2
  • Prevents downgrade attacks

  • Ensures modern cryptographic standards

  • Certificate verification enabled by default

2. Header Injection Prevention

CRLF Injection Protection

All user-controlled header values are sanitized before use:

  • Subject lines: CRLF replaced with spaces

  • Message-IDs: Validated RFC 5322 format

  • References: Each ID validated individually

  • Email addresses: CRLF characters rejected

# Sanitization removes/transforms dangerous characters
from simple_email_gw import sanitize_subject

subject = "Hello\r\nBcc: attacker@evil.com"
safe = sanitize_subject(subject)  # "Hello Bcc: attacker@evil.com"

3. Path Traversal Protection

Workspace Confinement

Attachment downloads are confined to a workspace directory:

# Post-write verification
real_path = os.path.realpath(file_path)
Path(real_path).relative_to(real_workspace)  # Raises if escaped
  • Symlink escape detection (TOCTOU race)

  • Path component sanitization

  • Hash-based unique filenames

4. Rate Limiting

Token Bucket Algorithm

Prevents abuse through request rate limits:

  • IMAP: 60 requests per minute per account

  • SMTP: 100 sends per hour per account

  • Per-account isolation

  • Automatic cleanup of expired requests

from simple_email_gw import RateLimiter

limiter = RateLimiter(rate=60, window=60)
if await limiter.acquire("account_name"):
  # Request allowed
  pass

5. Audit Logging

Security Event Tracking

All operations are logged for compliance:

Event

Log Level

Email sent

INFO

Authentication success

INFO

Authentication failure

WARNING

Rate limit exceeded

WARNING

Attachment download

INFO

Logs include:

  • Timestamp (UTC)

  • Account name

  • Operation details

  • Limited recipient info (privacy)

6. Recipient Whitelist

Outbound Email Restrictions

Optional whitelist restricts outgoing emails:

# Environment configuration
EMAIL_RECIPIENT_DOMAINS=trusted.com,partner.org
EMAIL_RECIPIENT_ADDRESSES=admin@company.com
  • Domain-based filtering

  • Address-based filtering

  • Case-insensitive matching

Known Security Considerations

IMAP Folder Name Sanitization

Status: Fixed (v0.1.0)

Folder names are sanitized with sanitize_folder_name() to prevent CRLF injection:

  • Rejects folder names containing \r or \n characters

  • Applied to all IMAP folder operations

SMTP Attachment Filenames

Status: Fixed (v0.1.0)

Attachment filenames are sanitized with sanitize_filename() to prevent CRLF injection:

  • Rejects filenames containing \r, \n, or \x00 characters

  • Applied before setting Content-Disposition header

IMAP Message ID Validation

Status: Fixed (v0.1.0)

Message IDs are validated with sanitize_message_id_numeric():

  • Ensures message IDs are numeric to prevent injection

  • Applied to all IMAP message operations

Rate Limiter Time Source

Status: Fixed

The rate limiter uses time.monotonic() for timing, preventing clock manipulation attacks.

Reporting a Vulnerability

Do not create a public issue for security vulnerabilities.

Please report security issues to:

  • Email: security@christophe.vg

  • Include: Description, reproduction steps, potential impact

Response Timeline:

  • Initial response: Within 48 hours

  • Assessment: Within 7 days

  • Fix timeline: Depends on severity

Security Best Practices

Secret Management

Environment Variables

Never commit credentials. Use environment variables:

# Good: Environment variable
export EMAIL_PASSWORD="app-specific-password"

# Bad: Hardcoded in code
password = "my-password"  # NEVER do this

Connection URIs

Never log connection strings (they may contain credentials):

# Bad: Logging the entire URI
logger.info(f"Connecting to {uri}")  # May expose password

# Good: Log only hostname
logger.info(f"Connecting to {host}:{port}")

OAuth2 Tokens

For OAuth2 authentication:

account = EmailAccount(
  name="gmail",
  imap_host="imap.gmail.com",
  smtp_host="smtp.gmail.com",
  username="user@gmail.com",
  oauth2_token="ya29.a0...",
  auth_method="oauth2"
)
  • Tokens should be refreshed regularly

  • Store in secure secret management

  • Never commit to version control

Development Security

Testing

Run security-focused tests:

make test  # Includes all security tests

Code Review Checklist

  • [ ] All user inputs sanitized

  • [ ] TLS 1.2+ enforced

  • [ ] Credentials never logged

  • [ ] Rate limits appropriate

  • [ ] Whitelist enforced

References