| Version | Supported |
|---|---|
| v1.4.x | ✅ Yes |
| v1.3.x | ✅ Yes |
| v1.2.x | ✅ Yes |
| < v1.2 | ❌ No |
We take security seriously. If you discover a security vulnerability in the ApertoDNS Protocol specification or reference implementation, please report it responsibly.
- Email: security@apertodns.com
- GitHub: Security Advisories
- Security.txt: https://www.apertodns.com/.well-known/security.txt
For sensitive reports, please encrypt your message using our PGP key:
- Key: https://www.apertodns.com/.well-known/pgp-key.txt
- Keyserver: keys.openpgp.org
- Fingerprint:
A65E 8CE4 5488 EEB9 5795 7B8E F7DB 6A1B 1CAA B9C0
- Description of the vulnerability
- Steps to reproduce the issue
- Potential impact assessment
- Suggested fix (if any)
| Stage | Timeline |
|---|---|
| Initial acknowledgment | Within 24 hours |
| Preliminary assessment | Within 72 hours |
| Fix development | Within 14 days (critical) / 30 days (other) |
| Public disclosure | After fix is deployed |
While we don't have a formal bug bounty program, we recognize security researchers:
- Credit in release notes and security advisories
- Hall of Fame listing on our website
- Swag and merchandise for significant findings
- TLS 1.2 minimum required
- TLS 1.3 recommended
- Valid, publicly-trusted certificates
- HSTS enabled with minimum 1-year max-age
- Certificate Transparency required
- Tokens must be cryptographically random (minimum 192 bits entropy)
- Token storage uses bcrypt (cost 12+) or Argon2id
- Basic Auth only for legacy DynDNS2 endpoint
- Bearer tokens for all modern endpoints
{provider}_{environment}_{random}
- provider: Provider identifier (lowercase, 3-20 chars, alphanumeric + hyphens)
- environment: "live" or "test"
- random: 32 chars base64url (192 bits)
Examples:
- apertodns_live_7Hqj3kL9mNpR2sT5vWxY8zA1bC4dE6fG (ApertoDNS)
- desec_live_xK9mNpR2sT5vWxY8zA1bC4dE6fG7Hqj3 (deSEC)
- duckdns_test_zA1bC4dE6fG7Hqj3kL9mNpR2sT5vWxY8 (DuckDNS)
All endpoints implement rate limiting to prevent abuse:
| Endpoint | Limit | Window |
|---|---|---|
| /update | 60 | 1 min |
| /bulk-update | 10 | 1 min |
| /status | 120 | 1 min |
| /nic/update | 60 | 1 min |
Hostname:
- Maximum 253 characters
- Each label 1-63 characters
- Alphanumeric and hyphens only
- No leading/trailing hyphens in labels
IP Address:
- Must be valid IPv4 or IPv6
- Must be globally routable (see Section 10 of protocol spec)
- 15 IPv4 ranges rejected per RFC 6890
- 9 IPv6 ranges rejected per RFC 6890
TTL:
- Integer between 60 and 86400
- HTTPS only - Webhook URLs must use TLS
- SSRF protection - URLs must not resolve to private IP ranges
- Signature verification - HMAC-SHA256 with timestamp
- Replay protection - 5-minute timestamp window
- Timeout - Maximum 10 seconds per delivery
const crypto = require('crypto');
function verifySignature(payload, signature, secret, timestamp) {
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - timestamp) > 300) {
return false;
}
const signedPayload = `${timestamp}.${payload}`;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}| Data | Purpose | Retention |
|---|---|---|
| Account, notifications | Until deletion | |
| Hostname | DDNS service | Until deletion |
| Current IP | DNS record | Until next update |
| Previous IP | Debugging | 7 days |
| Access logs | Security | 30 days |
| Token (hashed) | Authentication | Until revoked |
- Passwords in plaintext
- Full tokens in logs
- Geolocation data
- Browser fingerprints
- Tracking cookies
- Behavioral analytics
{
"timestamp": "2025-01-01T12:00:00.000Z",
"request_id": "req_xxx",
"method": "POST",
"path": "/.well-known/apertodns/v1/update",
"token_id": "tok_xxx",
"token_hint": "apertodns_live_xxxx...xxxx",
"response_status": 200,
"response_time_ms": 45
}All responses include:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'none'; frame-ancestors 'none'
Referrer-Policy: no-referrer
Cache-Control: no-store, no-cache, must-revalidate, private| Attack | Mitigation |
|---|---|
| Credential stuffing | Rate limiting, token format validation |
| Token enumeration | Constant-time comparison, no timing leaks |
| DNS rebinding | Strict hostname validation |
| SSRF via webhooks | Private IP range blocking |
| Replay attacks | Timestamp-bound signatures |
| Man-in-the-middle | TLS 1.2+ required |
- Network: TLS, HSTS, certificate pinning optional
- Application: Input validation, rate limiting, auth checks
- Data: Encryption at rest, minimal logging
- Monitoring: Anomaly detection, alerting
- Data export (Article 20)
- Account deletion (Article 17)
- Minimal data collection
- Transparent privacy policy
- OWASP Top 10 addressed
- CWE/SANS Top 25 considered
- Regular security audits
Security Team: security@apertodns.com
General Support: support@apertodns.com
Website: https://apertodns.com
Last Updated: 2026-01-22
Author: Andrea Ferro support@apertodns.com