Security
NextDNS Blocker is designed with security in mind, protecting your credentials and ensuring safe operation.
Credential Security
Section titled “Credential Security”API Key Storage
Section titled “API Key Storage”API credentials are stored in .env with restricted permissions:
# File permissions (Unix)chmod 600 ~/.config/nextdns-blocker/.env# Result: -rw------- (owner read/write only)Never Commit Credentials
Section titled “Never Commit Credentials”.gitignore patterns prevent accidental commits:
.env*.env.env.*Environment Variable Override
Section titled “Environment Variable Override”Credentials can be provided via environment for CI/CD:
export NEXTDNS_API_KEY=your_keyexport NEXTDNS_PROFILE_ID=your_idnextdns-blocker config pushFile Permissions
Section titled “File Permissions”Unix (macOS/Linux)
Section titled “Unix (macOS/Linux)”| File | Permissions | Description |
|---|---|---|
.env | 0600 | Owner read/write |
config.json | 0600 | Owner read/write |
pending.json | 0600 | Owner read/write |
*.log | 0644 | Owner write, world read |
Secure File Creation
Section titled “Secure File Creation”Files are created with restrictive permissions by default using write_secure_file():
# Internal implementationos.open(path, os.O_CREAT | os.O_WRONLY, 0o600)Windows
Section titled “Windows”Windows uses ACLs. Files are created with user-only access by default.
Input Validation
Section titled “Input Validation”Domain Validation
Section titled “Domain Validation”Before API calls, domains are validated:
- No empty strings
- Valid domain format (alphanumeric, hyphens, dots)
- Maximum length check
- No path components
# Valid"reddit.com""api.example.co.uk"
# Invalid (rejected)"https://reddit.com" # No protocol"" # Empty"../etc/passwd" # Path traversal attemptCredential Validation
Section titled “Credential Validation”API credentials are validated against patterns:
| Credential | Pattern | Minimum Length |
|---|---|---|
| API Key | Alphanumeric | 8 characters |
| Profile ID | Alphanumeric | 4 characters |
| Webhook URL | Strict URL format | - |
Schedule Validation
Section titled “Schedule Validation”Schedule entries are validated:
- Days: Lowercase weekday names only
- Times:
HH:MMformat (00:00-23:59) - Required fields: Both
startandend
API Security
Section titled “API Security”HTTPS Only
Section titled “HTTPS Only”All API communication uses HTTPS:
https://api.nextdns.io/...No HTTP fallback is allowed.
Request Authentication
Section titled “Request Authentication”API key is sent via header, not query string:
X-Api-Key: your_api_keyThis prevents key leakage in logs.
Rate Limiting
Section titled “Rate Limiting”Built-in rate limiting prevents API abuse:
| Setting | Default | Description |
|---|---|---|
RATE_LIMIT_REQUESTS | 30 | Max requests per window |
RATE_LIMIT_WINDOW | 60s | Time window |
Uses sliding window algorithm for accurate limiting.
Audit Logging
Section titled “Audit Logging”What’s Logged
Section titled “What’s Logged”All security-relevant actions:
| Event | Logged |
|---|---|
| Domain blocked | Yes |
| Domain unblocked | Yes |
| Panic mode start/end | Yes |
| Pending action created | Yes |
| Pending action cancelled | Yes |
| Configuration changes | Yes |
Log Format
Section titled “Log Format”2024-01-15 14:30:00 BLOCK reddit.com reason="outside schedule"2024-01-15 20:00:00 PANIC_START duration=60Log Protection
Section titled “Log Protection”Audit logs use append-only writes with file locking to prevent tampering during concurrent access.
PIN Protection
Section titled “PIN Protection”NextDNS Blocker includes optional PIN protection for sensitive commands, adding an authentication layer against impulsive behavior.
Protected Commands
Section titled “Protected Commands”When PIN is enabled, these commands require verification:
unblock- Remove domain from denylistallow- Add domain to allowlistconfig edit- Edit configurationconfig pull- Pull remote config
PIN Features
Section titled “PIN Features”| Feature | Default | Description |
|---|---|---|
| Minimum length | 4 characters | PIN must be 4+ characters |
| Maximum length | 32 characters | Upper limit for PIN |
| Session duration | 30 minutes | Valid session after verification |
| Max attempts | 3 | Attempts before lockout |
| Lockout duration | 15 minutes | Cooldown after max attempts |
| Removal delay | 24 hours | Waiting period to remove PIN |
PIN Commands
Section titled “PIN Commands”# Enable PINnextdns-blocker protection pin set
# Check PIN statusnextdns-blocker protection pin status
# Verify PIN and start sessionnextdns-blocker protection pin verify
# Remove PIN (creates pending action with 24h delay)nextdns-blocker protection pin removeSecurity Properties
Section titled “Security Properties”- PBKDF2-SHA256: PIN is hashed with 600,000 iterations (OWASP recommendation)
- Random salt: Unique salt per installation prevents rainbow table attacks
- Secure storage: Hash stored with
0600permissions - Brute force protection: Lockout after failed attempts
- Session-based: One verification covers multiple commands for 30 minutes
- Delayed removal: 24-hour delay prevents impulsive disabling
Configuration
Section titled “Configuration”PIN data is stored separately from config:
| File | Contents |
|---|---|
.pin_hash | Salt and hash (never contains plaintext) |
.pin_session | Session expiration timestamp |
.pin_attempts | Failed attempt timestamps |
Panic Mode Security
Section titled “Panic Mode Security”Cannot Be Cancelled
Section titled “Cannot Be Cancelled”Panic mode intentionally cannot be disabled early:
- Prevents bypass during weak moments
- Timer must expire
Hidden Commands
Section titled “Hidden Commands”During panic:
unblockis hiddenallowis hidden- Commands cannot be run directly
PIN During Panic
Section titled “PIN During Panic”When both panic mode and PIN are active:
- Panic mode takes priority
- Commands are completely hidden (not just PIN-protected)
- No authentication prompt is shown
Allowlist Sync Disabled
Section titled “Allowlist Sync Disabled”Scheduled allowlist sync is completely skipped during panic to prevent security bypasses.
File Locking
Section titled “File Locking”Concurrent Access Protection
Section titled “Concurrent Access Protection”State files use file locking:
| Platform | Mechanism |
|---|---|
| Unix | fcntl.flock() |
| Windows | msvcrt.locking() |
Prevents corruption from:
- Multiple sync processes
- Watchdog and manual operations
- Race conditions
Atomic Writes
Section titled “Atomic Writes”Configuration changes use atomic write pattern:
- Write to temporary file
- Sync to disk
- Rename to target
Best Practices
Section titled “Best Practices”Credential Management
Section titled “Credential Management”- Never share
.envfile - Use unique API key for this tool
- Rotate API key if compromised
- Don’t commit credentials to version control
Configuration Security
Section titled “Configuration Security”- Review config changes before applying
- Use
config validatebefore sync - Keep backups of working configuration
System Security
Section titled “System Security”- Keep Python updated
- Keep nextdns-blocker updated
- Monitor audit logs regularly
- Use panic mode when needed
Network Security
Section titled “Network Security”- Ensure DNS goes through NextDNS
- Block VPN/proxy if needed (in NextDNS)
- Verify HTTPS in all API calls
Threat Model
Section titled “Threat Model”Protected Against
Section titled “Protected Against”| Threat | Protection |
|---|---|
| Credential theft | File permissions, no logging of keys |
| API abuse | Rate limiting |
| Config tampering | File permissions |
| Panic bypass | Command hiding, no cancellation |
| Race conditions | File locking |
Not Protected Against
Section titled “Not Protected Against”| Threat | Reason |
|---|---|
| Root/admin access | Can read any file |
| Physical access | Can modify files offline |
| Keylogger | External to application |
| Browser cache | External to DNS blocking |
Reporting Vulnerabilities
Section titled “Reporting Vulnerabilities”If you discover a security issue:
- Do not open a public issue
- Email security concerns privately
- Include reproduction steps
- Allow time for fix before disclosure
See SECURITY.md for details.