Skip to content

Security

NextDNS Blocker is designed with security in mind, protecting your credentials and ensuring safe operation.

API credentials are stored in .env with restricted permissions:

Terminal window
# File permissions (Unix)
chmod 600 ~/.config/nextdns-blocker/.env
# Result: -rw------- (owner read/write only)

.gitignore patterns prevent accidental commits:

.env
*.env
.env.*

Credentials can be provided via environment for CI/CD:

Terminal window
export NEXTDNS_API_KEY=your_key
export NEXTDNS_PROFILE_ID=your_id
nextdns-blocker config push
FilePermissionsDescription
.env0600Owner read/write
config.json0600Owner read/write
pending.json0600Owner read/write
*.log0644Owner write, world read

Files are created with restrictive permissions by default using write_secure_file():

# Internal implementation
os.open(path, os.O_CREAT | os.O_WRONLY, 0o600)

Windows uses ACLs. Files are created with user-only access by default.

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 attempt

API credentials are validated against patterns:

CredentialPatternMinimum Length
API KeyAlphanumeric8 characters
Profile IDAlphanumeric4 characters
Webhook URLStrict URL format-

Schedule entries are validated:

  • Days: Lowercase weekday names only
  • Times: HH:MM format (00:00-23:59)
  • Required fields: Both start and end

All API communication uses HTTPS:

https://api.nextdns.io/...

No HTTP fallback is allowed.

API key is sent via header, not query string:

X-Api-Key: your_api_key

This prevents key leakage in logs.

Built-in rate limiting prevents API abuse:

SettingDefaultDescription
RATE_LIMIT_REQUESTS30Max requests per window
RATE_LIMIT_WINDOW60sTime window

Uses sliding window algorithm for accurate limiting.

All security-relevant actions:

EventLogged
Domain blockedYes
Domain unblockedYes
Panic mode start/endYes
Pending action createdYes
Pending action cancelledYes
Configuration changesYes
2024-01-15 14:30:00 BLOCK reddit.com reason="outside schedule"
2024-01-15 20:00:00 PANIC_START duration=60

Audit logs use append-only writes with file locking to prevent tampering during concurrent access.

NextDNS Blocker includes optional PIN protection for sensitive commands, adding an authentication layer against impulsive behavior.

When PIN is enabled, these commands require verification:

  • unblock - Remove domain from denylist
  • allow - Add domain to allowlist
  • config edit - Edit configuration
  • config pull - Pull remote config
FeatureDefaultDescription
Minimum length4 charactersPIN must be 4+ characters
Maximum length32 charactersUpper limit for PIN
Session duration30 minutesValid session after verification
Max attempts3Attempts before lockout
Lockout duration15 minutesCooldown after max attempts
Removal delay24 hoursWaiting period to remove PIN
Terminal window
# Enable PIN
nextdns-blocker protection pin set
# Check PIN status
nextdns-blocker protection pin status
# Verify PIN and start session
nextdns-blocker protection pin verify
# Remove PIN (creates pending action with 24h delay)
nextdns-blocker protection pin remove
  1. PBKDF2-SHA256: PIN is hashed with 600,000 iterations (OWASP recommendation)
  2. Random salt: Unique salt per installation prevents rainbow table attacks
  3. Secure storage: Hash stored with 0600 permissions
  4. Brute force protection: Lockout after failed attempts
  5. Session-based: One verification covers multiple commands for 30 minutes
  6. Delayed removal: 24-hour delay prevents impulsive disabling

PIN data is stored separately from config:

FileContents
.pin_hashSalt and hash (never contains plaintext)
.pin_sessionSession expiration timestamp
.pin_attemptsFailed attempt timestamps

Panic mode intentionally cannot be disabled early:

  • Prevents bypass during weak moments
  • Timer must expire

During panic:

  • unblock is hidden
  • allow is hidden
  • Commands cannot be run directly

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

Scheduled allowlist sync is completely skipped during panic to prevent security bypasses.

State files use file locking:

PlatformMechanism
Unixfcntl.flock()
Windowsmsvcrt.locking()

Prevents corruption from:

  • Multiple sync processes
  • Watchdog and manual operations
  • Race conditions

Configuration changes use atomic write pattern:

  1. Write to temporary file
  2. Sync to disk
  3. Rename to target
  1. Never share .env file
  2. Use unique API key for this tool
  3. Rotate API key if compromised
  4. Don’t commit credentials to version control
  1. Review config changes before applying
  2. Use config validate before sync
  3. Keep backups of working configuration
  1. Keep Python updated
  2. Keep nextdns-blocker updated
  3. Monitor audit logs regularly
  4. Use panic mode when needed
  1. Ensure DNS goes through NextDNS
  2. Block VPN/proxy if needed (in NextDNS)
  3. Verify HTTPS in all API calls
ThreatProtection
Credential theftFile permissions, no logging of keys
API abuseRate limiting
Config tamperingFile permissions
Panic bypassCommand hiding, no cancellation
Race conditionsFile locking
ThreatReason
Root/admin accessCan read any file
Physical accessCan modify files offline
KeyloggerExternal to application
Browser cacheExternal to DNS blocking

If you discover a security issue:

  1. Do not open a public issue
  2. Email security concerns privately
  3. Include reproduction steps
  4. Allow time for fix before disclosure

See SECURITY.md for details.