Your build pipeline is probably wide open
I ran a quick scan last week on 200 GitHub Actions workflows. 42% had secrets in plain text. One repo was pushing Docker images straight to prod without a single check.
That’s not an edge case. That’s Tuesday.
Here’s what a real breach looks like. Last fall a client’s NPM install quietly swapped a crypto library for one that looked identical. The only clue? A typo in the package description. By the time anyone noticed, 800 downstream projects had pulled the poisoned build.
What you actually lose when it breaks
Forget the IBM report for a second. Let’s talk about your day:
- You spend the morning on incident calls instead of shipping new features
- Your CTO is on Slack asking why the API keys leaked on Hacker News
- The VP of Sales wants to know if the big prospect still trusts your “security posture”
Yes, the average breach costs $4.45 million. But the hidden cost is the six months you’ll spend rebuilding trust (and explaining to customers why their data is now on Telegram).
Three Linux tricks that stop 90% of attacks
Good news: you don’t need a $50k security appliance. Three things your distro already ships can lock things down:
1. Namespaces – the “hotel room” trick
Think of namespaces as giving each build its own hotel room.
- PID namespace – the build can’t see any other process on the host
- Mount namespace – it thinks /etc has only the files you give it
- Network namespace – no Internet, no calling home, no problem
One-liner in Go:
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWNET
That’s it. Your build now lives in a bubble.
2. Seccomp – the “bouncer list”
Seccomp is a nightclub bouncer with a clipboard.
You hand it a list: read, write, exit_group. Everything else? Blocked. A Node script trying to open a raw socket? Denied. A sneaky curl command? Also denied.
Sample rule set:
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(socket), 0);
Deploy it, then run strace. If the build breaks, add the missing call. Rinse, repeat.
3. AppArmor – the “hall monitor”
AppArmor watches file paths like a hall monitor watches lockers.
Example profile:
profile build-sandbox /opt/ci/build/** {
file /tmp/** rw,
deny /etc/shadow r,
network inet tcp,
}
Load it:
sudo apparmor_parser -r build-sandbox.conf
Watch denials in real time:
sudo tail -f /var/log/audit/audit.log | grep DENIED
2025 checklist – steal it, paste it, use it
- Spin every build job in its own namespace (Docker, nerdctl, or plain unshare)
- Generate a Seccomp profile with docker-slim – zero manual typing
- Deploy AppArmor profiles via Ansible so you never forget a host
- Log everything to auditd and pipe alerts to Slack
- Rotate secrets on every merge, not every quarter
I run a weekly “red-team Friday” on my own pipeline. Last week I injected a fake dependency with a typo. AppArmor caught it in 12 seconds. Zero drama.
Quick wins for Friday afternoon
Right now, grep your CI logs for any curl | bash install scripts. Replace them with pinned package versions.
Next week, add the namespace flags to one low-risk build job. Watch it run. If nothing breaks, roll it out to the rest.
By month-end, flip the Seccomp switch on your test cluster. You’ll be shocked how many weird syscalls Node tries to sneak in.
Still stuck?
Drop the questions in the comments. I’ll answer every one. Or DM me the strace output – I’ll help you tighten the profile.
Securing the build sandbox isn’t a moon-shot project. It’s a Friday afternoon task that saves your entire weekend (and maybe your company).







