Permission Models Are Not Designed, They Accumulate
An is_admin boolean, then a role column, then a special case for one customer. Three years later nobody can say what a given user can do without reading the code, and an auditor is asking.
Deep dives, practical guides, and incident analyses from engineers who build Safeguard. No fluff, no vendor FUD — just what you need to ship secure software.
An is_admin boolean, then a role column, then a special case for one customer. Three years later nobody can say what a given user can do without reading the code, and an auditor is asking.
Empty error bodies get written by people worried about leaking internals, which is a real concern answered by the wrong control. Be precise about the caller's input, opaque about the system's state.
Nobody writes log.info(password). The leaks come from logging whole request bodies, exception objects, header maps and serialised domain objects, into a store replicated everywhere and retained for a year.
A forgeable key, a per-instance counter, a fail-open catch block and a fixed window all produce a limiter that runs, logs, appears on the architecture diagram, and blocks nothing. None shows up in the usual test.
A nullable tenant_id where NULL means global makes omission the unsafe state, and SQL NULL semantics mean the mistake never raises an error. The admin view looks full and correct while tenant-scoped rows are simply absent.
An SSO user carries your auth service's token, not your identity provider's. A verifier that accepts only the provider's tokens rejects exactly the users it was built for, and the symptom is a button that does nothing.
For a stored injection, confirming the bug and exploiting it are the same action. That is a property of the vulnerability, not a gap in anyone's product, and it changes what you should ask a DAST vendor.
Reading the first entry of X-Forwarded-For is reading user input. We captured what our load balancer actually sends, and it explains why a rate limiter can run for months without limiting anything.
param = decode(param) is as common as code gets. In a dataflow engine that resolves variables by looking backwards, it can recurse forever — and in Go the resulting stack overflow cannot be caught.
Weekly insights on software supply chain security, delivered to your inbox.
Your first fix PR is minutes away.
No sales call required, even your agent can complete the purchase over MCP.