Insider threat: the OpenAI case and how to protect yourself with Bun
An OpenAI engineer was arrested, accused of planting a listening device in the company's executive meeting room. The story ran in the SF Standard and reads like a spy movie script. But the real issue behind it is far less cinematic and far more common: insider threat. It's the risk that comes from people who already have a badge, access and the Wi-Fi password.
Before we go on, an honest disclaimer. The details of the case are still coming out, and I won't speculate about the person or the motive. An arrest is not a conviction. What interests me here is something else: what this kind of case shows about the way we build systems.
What happened, in a few lines
According to the report, an employee on the engineering side is suspected of bugging a room used by the company's leadership. No ransomware, no phishing, no zero-day. The person was already inside.
And this at one of the most targeted companies on the planet. OpenAI has model weights, roadmaps and billion-dollar negotiations going through those rooms. If it can happen there, it can happen at your 12-person startup.
Why insider threat is the risk everyone ignores
When we talk about security, our minds go straight to the outside attacker. Firewall, rate limit, WAF, CAPTCHA on the login page. Everything pointed outward.
But the mental model on a lot of teams is this: whoever got past authentication is trusted. Period.
Think about your project right now. How many people can:
- Run a
SELECTdirectly on the production database? - Read the production
.env? - Deploy without anyone reviewing it?
- Delete a log without leaving a trace?
On most small teams I know, the answer to all four is "everyone". Including the intern who joined last month. Including that CI token nobody remembers creating.
I'm not saying your coworker is going to bug you. I'm saying insider threat isn't always malice. Sometimes it's a stolen laptop, a compromised account, or someone who ran DELETE without WHERE at 6 p.m. on a Friday.
Trust is not access control.
What changes in the code: a trail that can't be erased
The physical bug is a building security problem. That's not your job. But the digital equivalent is: someone with legitimate access doing something illegitimate. And the first defense against that is knowing who did what, and being sure that record hasn't been tampered with.
A regular log doesn't solve it. If the person has database access, they delete the log line along with the damage. That's why I like hash-chained audit logs. Each record carries the hash of the previous one. Touch one, and the whole chain breaks.
With Bun you can do this without installing anything, using bun:sqlite and Bun.CryptoHasher:
import { Database } from "bun:sqlite";
const db = new Database("audit.db");
db.run(`CREATE TABLE IF NOT EXISTS audit (
id INTEGER PRIMARY KEY,
at TEXT NOT NULL,
actor TEXT NOT NULL,
action TEXT NOT NULL,
prev TEXT NOT NULL,
hash TEXT NOT NULL
)`);
// blocks UPDATE and DELETE directly on the database
db.run(`CREATE TRIGGER IF NOT EXISTS audit_no_update
BEFORE UPDATE ON audit BEGIN SELECT RAISE(ABORT, 'append-only'); END`);
db.run(`CREATE TRIGGER IF NOT EXISTS audit_no_delete
BEFORE DELETE ON audit BEGIN SELECT RAISE(ABORT, 'append-only'); END`);
const sha = (s: string) => new Bun.CryptoHasher("sha256").update(s).digest("hex");
export function audit(actor: string, action: string) {
const last = db.query("SELECT hash FROM audit ORDER BY id DESC LIMIT 1")
.get() as { hash: string } | null;
const prev = last?.hash ?? "genesis";
const at = new Date().toISOString();
const hash = sha(`${prev}|${at}|${actor}|${action}`);
db.run(
"INSERT INTO audit (at, actor, action, prev, hash) VALUES (?, ?, ?, ?, ?)",
[at, actor, action, prev, hash],
);
}
export function verify() {
let prev = "genesis";
for (const row of db.query("SELECT * FROM audit ORDER BY id").all() as any[]) {
if (row.prev !== prev) return { ok: false, brokenAt: row.id };
if (sha(`${row.prev}|${row.at}|${row.actor}|${row.action}`) !== row.hash) {
return { ok: false, brokenAt: row.id };
}
prev = row.hash;
}
return { ok: true };
}
Now, to be honest about the limits here. Anyone with write access to the file can drop the trigger and rewrite the whole chain from scratch. The hash doesn't prevent tampering. It only makes tampering detectable. To close that gap, send the latest hash somewhere the same person doesn't control: a bucket with locked retention, a Slack channel, a daily email. If yesterday's hash doesn't match today's chain, someone messed with it.
In PostgreSQL the idea is the same: an audit table with REVOKE UPDATE, DELETE for the application user, and the hash computed in the app or in a trigger.
How to plug this into an API with Bun
Creating the record has to be automatic. If it depends on someone remembering to call audit(), nobody will. A wrapper around the sensitive routes solves it:
import { audit } from "./audit";
type Handler = (req: Request, user: string) => Response | Promise<Response>;
const sensitive = (action: string, handler: Handler) => async (req: Request) => {
const user = req.headers.get("x-user-id"); // replace with your real auth
if (!user) return new Response("unauthorized", { status: 401 });
audit(user, `${action} ${new URL(req.url).pathname}`);
return handler(req, user);
};
Bun.serve({
routes: {
"/admin/export-users": sensitive("export", () => Response.json({ ok: true })),
"/admin/rotate-keys": sensitive("rotate", () => Response.json({ ok: true })),
},
fetch: () => new Response("not found", { status: 404 }),
});
Notice that the record happens before the action. If the action fails halfway, you still know someone tried. An attempt to export the user base at 3 a.m. is valuable information, whether it worked or not.
And yes, that x-user-id header is only there so the example fits on screen. If you trust a header the client sends, your insider threat problem becomes an anyone threat problem.
What I would change in the workflow tomorrow
Code is half the story. The other half is process, and it's usually the cheaper part.
Real least privilege. Nobody needs write access to production for day-to-day work. Create a read-only Postgres user for debugging and keep the write user only for the application and migrations.
Secrets out of the repo and out of Slack. If the production .env has ever gone through a DM, consider it leaked. Use your platform's secret manager and rotate anything old.
Tokens with an owner and an expiration date. Every CI or API token needs someone responsible for it and an expiration date. An eternal token with no owner is a back door waiting for someone to find it.
Mandatory review on deploy. A protected main branch takes five minutes to set up. It stops a single person, acting in bad faith or just tired, from pushing anything to production.
Same-day offboarding. When someone leaves the team, their access leaves with them. Not the following week. It's amazing how many companies find out months later that a former employee still had access to the admin panel.
None of these items is paranoia. It's hygiene. The same kind of care that makes you write a test before touching the shipping cost calculation.
Isn't this treating the team like suspects?
That's the objection I hear most, and I get it. Nobody wants to work in a place where everyone is being watched.
But an audit log isn't surveillance of people. It's a record of actions on critical systems. It protects the innocent too. When something disappears from the database, the log is what proves it wasn't you. Without it, all that's left is suspicion and fingers pointed in the meeting.
And there's a somewhat ironic detail in the OpenAI case. The accusation is precisely about someone spying on others without authorization. The antidote isn't more hidden surveillance. It's transparent control: everyone knows sensitive actions get logged, and the rules apply equally to the intern and the CTO.
My take
This case will make headlines for weeks because of the name involved. But the lesson for people who write code is boring and practical: the perimeter isn't the building's front door. It's every permission you hand out. Most systems I see are ready for the Russian hacker and wide open to anyone who already has a login.
If you only do one thing after reading this, take an inventory of who can write to production today. The list will probably scare you more than any bug in the meeting room.
If you want to see how I apply this kind of care to real systems, take a look at the projects I've delivered.
LinkedIn summary
An OpenAI engineer was arrested, accused of bugging the executives' meeting room. No ransomware, no phishing, no zero-day. The person was already inside. Most systems I see are ready for the Russian hacker and wide open to anyone who already has a login. Who on your team can run a SELECT in production, read the .env or deploy without review? On most small teams, the answer is "everyone". Trust is not access control. An audit log nobody can erase, least privilege and same-day offboarding are hygiene, not paranoia. I wrote about how to build a tamper-evident log with Bun in a few lines. The link is in the comments. #InformationSecurity #Bun #SoftwareDevelopment #DevSecOps #OpenAI