7.7 KiB
Security
goget implements multiple security features to protect both the client and server during file transfers. This document covers TLS configuration, certificate handling, checksum verification, PGP support, HSTS, and SSRF protection.
TLS / HTTPS
Default Security
- TLS 1.2 minimum — TLS 1.0 and 1.1 are disabled
- Certificate verification — Enabled by default against system CA bundle
- HTTP/2 support — Automatic ALPN negotiation
Certificate Pinning
Pin a specific certificate by its SHA-256 hash. This works across every TLS-bearing protocol goget supports: HTTPS, FTPS, Gemini, and WebDAVS.
goget --pinned-cert "a1b2c3d4e5f6..." --url https://example.com
goget --pinned-cert "a1b2c3d4e5f6..." --url ftps://ftp.example.com/file
goget --pinned-cert "a1b2c3d4e5f6..." --url gemini://geminiprotocol.net
goget --pinned-cert "a1b2c3d4e5f6..." --url webdavs://dav.example.com/file
If the leaf certificate's SHA-256 doesn't match, the connection is aborted.
SSH Host-Key Pinning (SFTP)
Pin the SSH host key for SFTP by its OpenSSH fingerprint (the same value
printed by ssh-keygen -lf ~/.ssh/known_hosts). Pinning takes precedence
over --ssh-insecure and the known_hosts file.
goget --pinned-host-key "SHA256:AAAAC3NzaC1lZDI1NTE5AAAAIE+HHi0MtRj4VPl8mdP8gniGZDRb0SZTdI2TPxRyCm1H" \
--url sftp://example.com/file
The raw lowercase-hex SHA-256 of the key wire format is also accepted.
Client Certificates (mTLS)
Authenticate the client to the server with mutual TLS:
goget --cert client.pem --key client.key --url https://mtls.example.com
Custom CA Bundle
goget --cacert custom-ca.pem --url https://internal.example.com
Insecure Mode
Disable all TLS verification (⚠ for testing only):
goget --insecure --url https://self-signed.local
SSLKEYLOGFILE
Log TLS session keys for Wireshark debugging:
goget --ssl-key-log tls.keys --url https://example.com
# Then: Wireshark → Preferences → TLS → (Pre-)Master-Secret log filename → tls.keys
HSTS (HTTP Strict Transport Security)
Per RFC 6797, goget maintains an HSTS cache that automatically upgrades HTTP connections to HTTPS for known hosts.
How It Works
sequenceDiagram
participant Client as goget
participant Server as Server
Client->>Server: GET http://example.com
Server-->>Client: 200 OK + Strict-Transport-Security: max-age=31536000
Client->>Client: Store: example.com → 365 days
Client->>Server: GET http://example.com/page (later)
Client->>Client: HSTS cache hit → upgrade to HTTPS
Client->>Server: GET https://example.com/page
Cache Location
~/.config/goget/hsts
Can be overridden with GOGET_HSTS environment variable or --hsts-file.
Cache Format
[
{
"host": "example.com",
"include_subdomains": true,
"expires": "2027-06-01T00:00:00Z"
}
]
Expired entries are automatically pruned on load.
Checksum Verification
Verify file integrity after download:
Direct Hash
goget --checksum "a1b2c3d4e5f6..." --checksum-algo sha256 --url https://example.com/file.zip
Supported algorithms:
| Algorithm | Flag Value | Hash Length |
|---|---|---|
| SHA-256 | sha256 |
64 hex chars |
| SHA-512 | sha512 |
128 hex chars |
| SHA3-256 | sha3-256 |
64 hex chars |
| SHA3-512 | sha3-512 |
128 hex chars |
| BLAKE2b | blake2b |
128 hex chars |
| MD5 | md5 |
32 hex chars |
Checksum File
Supports standard SHA256SUMS format:
# SHA256SUMS file:
# a1b2c3d4... file.zip
# e5f6a7b8... *file.tar.gz
goget --checksum-file SHA256SUMS --url https://example.com/file.zip
Both plain (file.zip) and binary-mode (*file.tar.gz) formats are supported.
Error Handling
On mismatch:
Checksum mismatch
Expected: a1b2c3d4...
Actual: e5f6a7b8...
The error is a typed core.GogetError with Type: "CHECKSUM" and Details["expected"] / Details["actual"].
PGP / GPG
Signature Verification
Verify PGP detached signatures:
# With explicit signature file
goget --pgp-verify --pgp-sig file.sig --pgp-key public.key --url https://example.com/file
# Auto-detect signature file (tries: file.asc, file.sig, file.gpg)
goget --pgp-verify --pgp-key public.key --url https://example.com/file
Decryption
Decrypt PGP-encrypted files:
# Decrypt with key and passphrase
goget --pgp-decrypt --pgp-key private.key --pgp-passphrase "secret" --url https://example.com/file.gpg
# Read passphrase from file (safer)
goget --pgp-decrypt --pgp-key private.key --pgp-passphrase-file pass.txt --url https://example.com/file.gpg
The decrypted file replaces the encrypted one:
file.gpg→filefile.pgp→filefile.asc→file- Other →
filename.decrypted
Note: PGP functionality uses
golang.org/x/crypto/openpgp, which is frozen. A replacement will be provided in a future release.
SSRF Protection
By default, goget blocks connections to private and internal IP ranges:
| Range | CIDR | Description |
|---|---|---|
10.0.0.0/8 |
Private | RFC 1918 |
172.16.0.0/12 |
Private | RFC 1918 |
127.0.0.0/8 |
Loopback | Internal |
169.254.0.0/16 |
Link-local | Auto-configuration |
::1/128 |
IPv6 loopback | Internal |
IPv4-Mapped IPv6 Normalization
DNS-controlled IPv4-mapped IPv6 addresses (e.g. ::ffff:10.0.0.1) are now normalized to plain IPv4 before the private-IP check. This prevents an attacker from reaching internal hosts through DNS responses that embed IPv4 addresses in IPv6 form. Covered by a 17-case unit test in the transport layer.
Override with --allow-private:
goget --allow-private --url https://internal.example.com
DNS Security
Custom Resolvers
Bypass system DNS for specific queries:
goget --dns-servers 1.1.1.1,8.8.8.8 --url https://example.com
IPv6-First
The transport dialer prefers IPv6 and only falls back to IPv4 when no IPv6 address is available. This reduces NAT-related attack surface:
# IPv6 only (abort if no IPv6)
goget --no-ipv4 --url https://example.com
Credential Safety
Safe Error Logging
When a URL contains user credentials (https://user:pass@example.com), core.SafeURL() strips them from error messages and logs:
// Original: https://admin:secret@api.example.com/data
// Logged: https://api.example.com/data
OAuth Error Sanitization
Non-2xx OAuth responses are sanitized to extract only the structured error / error_description fields (RFC 6749 §5.2). Providers that echo client_secret or other secrets in their error response bodies can no longer leak them into goget logs or error displays.
Config Sanitization
config.Save() strips sensitive fields before writing to disk:
auth.passwordauth.oauth.client_secretauth.oauth.access_tokenauth.oauth.refresh_token
File Permission Hardening
Configuration files (config.toml), resume metadata sidecars (.goget.meta), and atomic temp files are written with mode 0600 (owner-only), so OAuth tokens, source URLs, and downloaded payloads are never world-readable on multi-user systems.
Environment Variables
GOGET_CONFIG— alternative config file pathGOGET_PASSWORD— password override (no file storage)GOGET_HSTS— alternative HSTS cache pathNO_COLOR— disable color output
Timeouts & Limits
| Feature | Default | Description |
|---|---|---|
| Connection timeout | 30s (auto) | Smart calculation based on file size |
| Max total time | — (--max-time) |
Abort if exceeded |
| Max file size | — (--max-filesize) |
Abort if server response exceeds limit |
| Max retries | 3 | Exponential backoff with 30s cap |
| Retry delay | 1s initial, 2× multiplier | Configurable via --retry-delay |