Blog
Go, Rust, Linux, cryptography and UK privacy law. One properly researched article a day.
Page 2 of 3. Working notes from a software engineer who spends the day in Go, Rust and Linux and the evening reading legislation. Each post takes one specific question and answers it properly: why a worker pool deadlocks, what fsync really promises, how to enrol a TPM into LUKS without locking yourself out, what a technical capability notice can actually compel. Step-by-step how-tos sit alongside the deep dives, everything is checked against source code or primary legislation, and nothing is padded to hit a word count.
Subscribe with the Atom feed to get each post as it lands.
-
Postgres Advisory Locks in Go: Cheaper Than a Distributed Lock Service
How to use Postgres advisory locks from Go for cron dedup and leader election, and the connection-pooling pitfall that breaks them silently.
-
Hybrid Post-Quantum TLS 1.3: Why ML-KEM Rides Alongside ECDHE
Why TLS 1.3's post-quantum key exchange combines ML-KEM with ECDHE instead of replacing it, and what that costs in handshake size.
-
Rural Broadband and CGNAT: Why Self-Hosting Needs a Reverse Tunnel
Starlink and most 4G home routers hide you behind CGNAT, so port forwarding does nothing. Here's how a reverse WireGuard tunnel fixes it.
-
Ed25519 vs ECDSA: How Deterministic Nonces Ended a Recurring Bug
How a reused ECDSA nonce leaks a private key, why Sony and Android wallets fell to it, and how Ed25519 designs the whole bug class out.
-
Flipper Blue++: The Bluetooth Stack the Flipper Zero Was Built For
Why stock Flipper Zero firmware cannot scan or connect over BLE, the three patches that unlock the full stack, and how to drive it from your own app.
-
Go HTTP Response Bodies: Why Close Alone Loses Connections
Closing a Go HTTP response body prevents leaks, but HTTP/1 connection reuse depends on reaching EOF. Learn when to drain, cap or abandon a body.
-
Go's iter.Seq and Range-over-Func: What Iterators Actually Cost
How range-over-func actually compiles in Go 1.23, why non-local control flow needs hidden state, and where iter.Seq stops being free.
-
Go's DisallowUnknownFields: Catching Silent JSON Typos
encoding/json ignores JSON fields it doesn't recognise by default. DisallowUnknownFields turns that into an error, but only if you use it correctly.
-
Rust's Pin and Self-Referential Futures: Why async Needs It At All
Why compiling an async fn into a state machine makes the result self-referential, and how Rust's Pin type stops the compiler from moving it unsafely.
-
Rust's mpsc Backpressure: tokio vs std Under Load
Why tokio::sync::mpsc suspends a task while std::sync::mpsc blocks an OS thread, and why mixing the two on one runtime causes stalls.
-
Go http.Server Timeouts: Why Slowloris Still Gets Through
Learn which Go HTTP timeouts cover slow headers, request bodies and keep-alive gaps, and which mistakes leave connections exposed.
-
Go's time.After: The Timer Leak Hiding in Every select Loop
How a select loop that calls time.After every iteration quietly piles up timers on old Go, and why Go 1.23 changed the rules.
-
Why Your Go Worker Pool Deadlocks: An Unbuffered Channel Post-Mortem
A Go worker pool that deadlocks under load, traced back to an unbuffered results channel, with the fix and why bigger buffers only postpone the problem.
-
Hardening SSH: The Ciphers, MACs and Key Exchanges to Disable
A walkthrough of sshd_config's KexAlgorithms, Ciphers and MACs directives: what to strip out, why, and how to verify the change without locking yourself out.
-
Go's sync.Once Isn't a Mutex: What Actually Happens When f() Panics
sync.Once does not retry after f() panics: it quietly marks itself done, while OnceValue re-panics forever. Verified against the Go source.
-
Certificate Transparency: What CT Logs Prove About a Certificate
CT logs make TLS certificate issuance publicly auditable, but they do not validate domain control, check revocation or stop mis-issuance. The actual guarantee.
-
How to Set Up Secure Boot with Your Own Keys Using sbctl
Create, enrol and maintain your own UEFI Secure Boot signing keys on Linux with sbctl, without turning the next reboot into a recovery exercise.
-
Rust Has No Async Drop: Why You Can't Await in a Destructor
Rust has no async destructor, and it isn't an oversight. Why Drop::drop can't await, and the spawn/block_on/explicit-close patterns people use instead.
-
Go's %w Wrapping: One Missing Verb and errors.Is Silently Fails
A single %v where you meant %w compiles cleanly and passes go vet, but it quietly severs the error chain that errors.Is depends on.
-
Ransomware-Resistant Backups with Borg Append-Only Repositories
Configure BorgBackup with a server-enforced append-only repository, so a compromised client can add backups but never delete or rewrite them.
-
Go's GOMAXPROCS Ignores Container CPU Limits, and Your Pod Pays
A Go service capped at 0.5 CPU in Kubernetes still spins up dozens of OS threads and gets throttled. Why GOMAXPROCS cannot see the limit, and how to fix it.
-
Subject Access Requests: What UK GDPR Lets Organisations Redact
The DPA 2018 exemptions that let organisations lawfully redact a subject access request, and the patterns of overreach that turn a redaction into a breach.
-
Remote LUKS Unlocking on a Headless Server with Dropbear
A step-by-step guide to embedding a minimal Dropbear SSH server in initramfs so you can type a LUKS passphrase over the network on a headless server reboot.
-
CAP_NET_BIND_SERVICE vs setuid Root: Binding Port 80 in Go
Binding to port 80 as a non-root Go process without setuid tricks, using Linux capabilities, CAP_NET_BIND_SERVICE, setcap and systemd's AmbientCapabilities.
-
bcrypt's 72-Byte Truncation: A Password Bug Hiding in Plain Sight
bcrypt silently ignores everything past the 72nd byte of a password. Why the limit exists, how it produces real collisions, and how to handle it properly in Go.
-
FIDO2 Hardware Keys for SSH with Resident Keys
A practical guide to generating resident FIDO2 SSH keys with ssh-keygen, setting a PIN, and recovering the credential onto a new machine with ssh-keygen -K.
-
Timing Side Channels in Go: Why == on a MAC Is a Security Bug
Comparing a computed HMAC with == looks correct and compiles fine, but it leaks timing information an attacker can use to forge a valid MAC byte by byte.
-
SCM_RIGHTS: How systemd Hands Off Sockets Over a Unix Socket
How SCM_RIGHTS lets one Unix process hand an open file descriptor to another, with a working Go example and a look at where systemd genuinely uses it.
-
How to Set Up Fail2ban to Stop SSH Brute-Force Attacks on Linux
Install and configure fail2ban on Linux to block SSH brute-force attempts automatically: jail.local, the systemd journal backend and the common pitfalls.
-
Unix Sockets vs TCP Loopback: The Localhost Attack Surface in Go
Binding to 127.0.0.1 feels private, but loopback TCP has no concept of "who's asking". Unix domain sockets do, and Go makes using them easy.
-
Rust's Drop Order: Why RAII Cleanup Can Run in the Wrong Sequence
Rust drops locals in reverse order but struct fields in declaration order. That asymmetry is a documented footgun for locks, file handles and temp directories.
-
Mutual TLS Between Two Go Services with Your Own Private CA
Build a minimal private CA in Go and configure two services to authenticate each other with mutual TLS, including the identity check most tutorials skip.
-
Go's os.Exit Skips Every Deferred Function, Including Cleanup
os.Exit ends a Go process immediately without unwinding the stack, so no deferred function runs. Why, and how to structure main() so it does not bite you.
-
filepath.Clean Won't Stop Symlink Escapes in Go, but openat2 Will
Why lexical path checks cannot stop symlink escapes, and how Linux openat2 provides race-resistant directory confinement for Go services.
-
How to Set Up a Default-Deny Firewall with nftables on Linux
Build, test and persist a default-deny nftables firewall without breaking IPv6, flushing container rules or locking yourself out of SSH.
-
Go's Default HTTP Client Has No Timeout, and Tutorials Ship It
http.Get and http.DefaultClient have no timeout at all. Here's exactly which phases of a request are bounded, which aren't, and how to fix it properly.
-
Nonce Reuse in AES-GCM: Why Once Is Enough to Break Everything
AES-GCM fails catastrophically, not gracefully, if a nonce is ever reused. Here's what actually breaks, why, and how to stop it happening.
-
How to Set Up a WireGuard Site-to-Site VPN Between Two Linux Servers
Join two LANs over WireGuard: key generation, subnet routing, firewall rules, MTU pitfalls and how to verify the tunnel is actually carrying traffic.
-
The Data (Use and Access) Act 2025: What Changed for UK GDPR
The Data (Use and Access) Act 2025 amends UK GDPR rather than replacing it: new lawful bases, looser automated decision rules and a new transfer test.
-
HKDF Explained: Why Hashing Key Material Isn't Key Derivation
A look at why sha256(sha256(secret)) is not key derivation, what HKDF's extract-and-expand construction actually buys you, and how to use it correctly in Go.
-
Network-Wide DNS-over-TLS on Linux with Unbound
Run Unbound as a validating, caching DNS-over-TLS resolver on Linux so every device on the network gets encrypted, DNSSEC-checked lookups with no per-app setup.
-
context.Context Cancellation Doesn't Stop Your Goroutines
context cancellation in Go is cooperative, not preemptive: it closes a channel and nothing more. Here's where that quietly fails, and how to actually stop work.
-
Why io_uring Won't Automatically Speed Up Your Network Service
io_uring's benchmarks are real, but most of its wins are in storage and syscall-bound workloads. Why bolting it onto a network service often buys nothing.
-
Automated Encrypted Backups with restic and a Remote SFTP Target
A practical guide to backing up a Linux machine with restic over SFTP: repository setup, password handling, systemd timers, retention, and verifying restores.
-
Technical Capability Notices: What the IPA Can Compel Companies to Do
What a technical capability notice under the Investigatory Powers Act can require, why the Apple ADP dispute turned on one phrase, and why it is secret.
-
PECR and Cookie Banners: Why Most 'Reject All' Buttons Fail
Why UK cookie banners with a working 'reject all' button still breach PECR, from consent-timing bugs to IAB TCF legitimate interest loopholes.
-
GPG Subkeys: Keep Your Master Key Offline, Sign and Encrypt Daily
How to split a GPG identity into an offline certify-only master key and day-to-day sign, encrypt and auth subkeys, with backup and rotation steps.
-
TLS Hides Your Data, Not Your Behaviour
TLS encrypts the contents of your connections, but packet sizes, timing, SNI and DNS still leak enough to fingerprint sites, videos and even keystrokes.
-
SQLite WAL Mode: Why Writers Still Block, and How Go Makes It Worse
WAL mode lets SQLite readers and writers coexist, but writers still queue for one lock. Go's connection pool can turn that into 'database is locked' errors.
-
How to Set Up SSH Certificate Authentication with Your Own Minimal CA
Replace sprawling authorized_keys files with a small self-hosted SSH certificate authority: user and host certificates, principals and revocation.