Articles
Go, Rust, Linux, cryptography and UK privacy law. One properly researched article a day.
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.
-
Why an ESP8266 Web Server Freezes When a Handler Calls delay()
An ESP8266 web handler that calls delay() keeps WiFi alive but stops every other request. See why it happens and how to fix it with millis().
-
Why Your Async Task Never Yields and Starves Its Neighbours
An async task only gives up its thread at an await that returns Pending. Here is how a tight loop starves tokio neighbours, and three ways to fix it.
-
Why Your API Retry Creates Two Orders: Idempotency Keys in Go
A client times out, retries, and you ship two orders. Here is how an Idempotency-Key header fixes it, with a small Go middleware and its edge cases.
-
Can a One-Person Mail Server Be Handed an IPA Notice?
A self-hosted mail server can fall inside the IPA's definition of a telecommunications operator. Here is what that does and doesn't mean in practice.
-
Is Your Server-Side A/B Test Cookie Exempt Under PECR?
Assigning A/B variants on the server doesn't dodge PECR if you set a cookie. Here is when the statistical purposes exception covers it, and when it doesn't.
-
Sending on a Go Channel You Never Close Is Fine, Until It Isn't
Closing a Go channel is a message to receivers, not memory cleanup. Here is when skipping close is harmless, and when it hangs or leaks goroutines.
-
Your HSM Key Is Non-Extractable Until Someone Wraps It
A PKCS#11 key marked non-extractable can still leave the HSM if a wrapping key is readable. Here is how the attack works and which attributes stop it.
-
A Deleted Chat Message Is Usually Just a Flag on the Server
Deleting a chat message usually sets a flag, then leaves copies in dead rows, the WAL, search indexes, caches and backups. Here is where they hide.
-
Go Writes to a Closed Socket Get EPIPE, Not SIGPIPE (Mostly)
Why a Go program usually survives writing to a closed socket, the cases where SIGPIPE still kills it, and how to handle the EPIPE error properly.
-
What Actually Makes a Rust Async Fn Bigger Across an Await
An async fn's size depends on what is live across each await, not how many there are. Measure it, shrink it, and see why recursion needs Box::pin.
-
Why O_APPEND Writes Don't Interleave, Until NFS
Two processes appending to one log file are safe on a local filesystem. Over NFS the guarantee quietly disappears, and here is why and what to do instead.
-
Does a Legitimate Interests Assessment Cover Your Server Monitoring?
Security monitoring is a recognised legitimate interest under UK GDPR, but an LIA only covers what you wrote down. Here is where the cover runs out.
-
Why a Warrant Can Reach Your Metadata but Not Your Message Content
A warrant can only compel what a provider holds. With end-to-end encryption that is routing data and ciphertext, not your messages. Here is the mechanics.
-
Why Your Wrapped Data Key Is Useless Without Its Context Binding
A wrapped data key that any record can unwrap lets someone with database write access swap rows. Bind it to its context with AAD, shown in Go.
-
Why a Read-Only Go Map Still Needs Synchronisation
A map with no writes can still publish stale or mutable data. Learn when concurrent reads are safe, when they race, and how to publish snapshots.
-
Your Go Service Logs the Secret You Thought Was Redacted
A Go type that redacts itself in slog still leaks through URL errors, struct dumps and header logging. Here are the four leaks and how to close each.
-
Can a Manufacturer Legally Brick Your Device After a Repair?
A UK reading of what happens when an update disables a repaired device: contract terms, the Consumer Rights Act, and the Computer Misuse Act angle.
-
Why age Is a Better Fit Than GPG for Encrypting a Single File
age drops keyrings, trust prompts and algorithm negotiation. Here is what encrypting files with it looks like, and where GPG still wins.
-
Why ESP32 Light Sleep Drops Your WiFi Without Telling You
Calling esp_light_sleep_start() with WiFi up can leave a stale link and dead sockets. Why it happens, and how automatic light sleep keeps the connection.
-
Your Encryption Key in an Environment Variable Is Readable via /proc
Environment variables look private, but /proc/PID/environ exposes them. See what unsetenv misses and how to pass a key via a file or systemd credentials.
-
Why Ctrl-C Leaves Your Terminal Broken Mid-Prompt
A CLI that turns off echo or reads raw keys changes terminal modes, and a signal skips the restore. Here is why it happens, and how to fix it in Go.
-
Why Your Rust Vec of Futures Runs Sequentially Until You Spawn Them
A Vec of futures does nothing until polled. See why awaiting them in a loop is sequential, and when to use join_all, spawn or buffer_unordered.
-
Why Your Port Scan Misses Half the Open Ports on a Go Target
Five reasons nmap reports fewer open ports than a Go service really has: port ranges, IPv6, bind addresses, UDP and a full accept backlog, plus ss to check.
-
Why rename() Is Atomic Within a Mount and mv Across Mounts Is Not
rename(2) is atomic because it only edits directory entries. Across mounts it fails with EXDEV and mv copies then deletes. Here is the safe pattern.
-
Why Your Privacy Impact Assessment Should Be a Pull Request Check
A DPIA written once and filed away goes stale on the next migration. Here is how to wire the review into pull requests so it tracks the code.
-
Why rm Can Delete a File You Cannot Write To, and When It Can't
Deleting a file needs permission on its directory, not the file. Here is what rm checks, plus the sticky bit, chattr +i and read-only mounts that block it.
-
Dropping a Tokio JoinHandle Detaches the Task, It Doesn't Cancel It
Why dropping a tokio JoinHandle leaves the task running, how abort() and AbortHandle really cancel it, and what a task can still do after you ask it to stop.
-
Why Go Upload Handlers Leave Temp Files After a Disconnect
A client drops mid-upload and your temp directory fills with orphaned files. Here is where Go's multipart cleanup stops, and a handler pattern that never leaks.
-
Build a Tiny HTTP Server That Knows When to Stop
A small Go HTTP server that bounds headers and bodies, sets useful deadlines, and shuts down cleanly when the process gets a signal.
-
Can Reading Someone's Records at Work Be a Crime Under DPA s.170?
Section 170 of the DPA 2018 can make looking at personal data without the controller's consent a criminal offence. Here is what it covers and the defences.
-
Your AES-GCM Associated Data Is Only Checked If You Bind It
AES-GCM authenticates associated data only when you pass the right bytes on both sides. Four Go mistakes that make AAD a no-op, and a test that catches them.
-
A nil *MyError Returned as error Is Not nil
Return a nil *MyError from a function declared to return error and err != nil is true. How Go interfaces store a type and a value, and how to fix it.
-
Why a Process Still Holds a flock After You Closed the File
You closed the lock file and the lock is still there. Why flock outlives close(), how a leaked fd keeps it alive, and how to find the holder in /proc.
-
Your Signal Safety Number Is Only Useful If You Compare It
A Signal safety number only protects you once you compare it. What it encodes, what a change means, and how to check it properly.
-
Why Your Go Pipeline Hangs When One Stage Returns Early
A Go pipeline stage that returns early leaves upstream goroutines blocked on a send forever. See why wg.Wait hangs and how context cancellation fixes it.
-
Why an ESP8266 Reboots on an HTTPS POST When Heap Runs Short
TLS buffers, a fragmented heap and a String-built body can reset an ESP8266 mid-POST. How to read the crash, measure free blocks and shrink the handshake.
-
Rotating a Key Protects Nothing Until Old Data Is Re-Encrypted
Why a key rotation only protects new writes, how a leaked old key still opens every old ciphertext and backup, and how to re-encrypt in Go safely.
-
A 256-Bit Backup Key Is Only as Strong as Its Passphrase
Your backup tool may use AES-256, but the passphrase sets the real security level. Here is the arithmetic, and how to pick one that holds up.
-
Your UPS Can Only Shut the Server Down If It Can Talk to It
A UPS with no data link just gives you a few more minutes before the same hard crash. Set up NUT, tune the low-battery point, and test it properly.
-
Two OIDC Providers, Two Readings of the Spec, One Broken Login
Issuer trailing slashes, audience arrays, stringly booleans and unverified emails: where OIDC providers differ and how to write a verifier that copes.
-
Your Go Hash Is Wrong Because You Hashed the Whole Buffer
Hashing buf instead of buf[:n] gives a stable but wrong digest that only misbehaves once a buffer is reused. How to spot it, fix it and test for it.
-
How Long Should You Keep Web Server Access Logs, Really?
UK GDPR gives no number for access log retention. Here is how to pick one you can defend, and set it up with logrotate and nginx IP truncation.
-
When the Error Path Becomes the Security Boundary
Errors decide what your system reveals, retries, cleans up and permits. Treat failure handling as security-critical code, not diagnostic plumbing.
-
Power Cuts Turn Home Labs into Distributed Systems
A power cut turns a home lab into a distributed system. Learn to design for partial failure, clean recovery, stale state and safe restarts.
-
Write Files Without a Cleanup Race with O_TMPFILE
Linux's O_TMPFILE creates an unnamed inode, so failed writes vanish on close. Learn the Go syscall sequence for safe publication and durable files.
-
Your Reverse Proxy Can Create More Connections Than Clients
A reverse proxy can multiply sockets through HTTP/2 fan-out, retries and pools. Learn how to measure the real limits and cap them safely.
-
When Can You Keep a User's Data After They Object?
A practical UK GDPR guide to objections: when you must stop processing, when you can retain data, and why suppression is not erasure.
-
Why a Blocking Call in an async Rust Task Stalls Other Requests
One std::thread::sleep or sync file read in a Tokio task can freeze unrelated requests. See why it happens, how to reproduce it, and how to fix it.
-
Your Analytics Pipeline Still Holds the IP You Dropped
You strip the IP from the event payload, then find it in access logs, error lines, traces and queue headers. Here is how to hunt down each copy and remove it.
-
Hashing User IDs Doesn't Make Your Analytics Anonymous
Hashing a user ID does not anonymise it. Why pseudonymised analytics data stays personal data under UK GDPR, and what pseudonymisation does buy you.