Skip to content

Security is not an afterthought

Posted by author in the category "Opinions"

Anyone can build a journaling application, but can you build one where user content is end-to-end encrypted and unreadable to the service operator by design?

The majority of "developers" out there wouldn't even know where to start, let alone how to architect such a system, without solely relying on AI. This is not me taking a purist standpoint; it's an observation from which I deduce that understanding security is a privilege. But I'd argue that what's truly gatekeeping understanding of security is human nature, which tends towards paths of least resistance.

High-level security goals like Zero Knowledge architecture or End-to-End Encryption (E2EE) remain foreign to most because they lack a foundational understanding of the basics.

Security represents friction.

But security doesn't represent friction when you've trained your mind to look for loopholes and all the ways malicious actors might act. That demands a change of perspective. If you don't care about the hundreds of unvetted dependencies you're pulling in today, you'll never be able to build a secure system tomorrow.

The dependency slop

Recently, I commented on the "insane amount of third-party dependencies" in the React Native ecosystem. The immediate retort was: "And you prefer to have all that maintained by yourself?"

This misses the point entirely. If there's no reasonable explanation why it should be included as a dependency, it has no business existing in the codebase of projects I manage. If it can't be properly vetted (including all of its transient dependencies), it has no business being included.

Non-negotiable. Cry about it if you don't like it.

The anatomy of a supply chain attack

Take react-native-screens. It's a fantastic, essential package. But look at its transients: react-freeze and warn-once.

react-freeze is essentially 30 lines of code, a trivial suspense wrapper! warn-once is a simple Set to track developmental log messages. Are you telling me that you can build a complex library like react-native-screens, but you can't write 30 lines of code or manage your own logs!?

Or look at detox from Wix. A serious tool from a serious company. Yet it depends on find-up, which pulls in locate-path and p-locate. We are pulling in an entire tree of dependencies just to traverse a file system, a task any developer should be able to solve with a simple recursive function using fs!

This is a culture problem. When you include a package, you aren't just trusting that developer; you are trusting every developer they ever trusted, and every developer those developers trusted. Every "convenience" library is a potential backdoor you didn't see coming.

NIST defines the software supply chain as a collection of steps that create, transform, and assess the quality of software (SP 800-204D)

For most modern developers, it's just a black box. Jira ticket has been closed, who cares...

If you think I'm being dramatic, look at the data. 97% of audited commercial codebases contain open source (Black Duck OSSRA 2025). The average application pulls in 911 open-source components.

The weight of this technical debt... My God... 86% of codebases contain open-source vulnerabilities, and 81% have high or critical-risk ones. According to the Veracode 2025 State of Software Security report, 70% of critical security debt stems from third-party code.

We are living through a period of unprecedented supply chain aggression, and the answer to that is... Nothing?

  • September 2025 (NPM): A maintainer phishing attack on qix (Josh Junon) compromised over 18 core packages including chalk, debug, and ansi-styles. These are packages with billions of weekly downloads.
  • The Shai-Hulud Worm: A self-propagating worm that hit over 500 NPM packages in late 2025, stealing secrets and auto-publishing malicious versions using hijacked tokens.
  • February 2025 (Go): A typosquat on BoltDB introduced a backdoor via proxy caching, allowing for remote code execution.
  • March 2024 (XZ Utils): The now-legendary CVE-2024-3094, where a long-term maintainer compromise nearly introduced a backdoor into the very fabric of Linux SSH servers.

You've found yourself at a crossroads...

If you're operating in a DevSecOps environment, there are two directions you can take.

1. The Purist

This is my preferred path, and this is where my personal opinion lies. Minimize dependencies. Write more in-house code. It shrinks the attack surface. Fewer components mean fewer vulnerabilities to track. People will argue this "reinvents the wheel," but I'd rather build a wheel I understand than use a stolen one that's rigged to explode in five years.

2. The Pragmatist

This is the dominant path in most fast-moving organizations, and it's the one which I believe should be adopted, because let's be honest, my personal opinions don't matter. I'm hired to get the job don, not to be a purist.

So this is my professional opinion. If you must rely on 900+ dependencies, you cannot do it with blind trust. You need automated guardrails.

Adversarial thinking & mitigation

If you don't care about long-term support and stability, you've probably never worked on a project for more than a weekend. 2, 5, or 10 years down the line, these dependencies matter.

We must introduce adversarial thinking as a bedrock of education. Adversarial thinking means shifting for the end goal from "making it work" to "causing catastrophic damage." It means habitually adopting an attacker's lens.

Assume malice, because every user is either stupid or malicious, and every dependency is expansion of the supply chain attack surface. Question every assumption, because if you need is-stream to check if something's a Node.js Stream, you're already a lost cause in my books. Just try to understand how a system breaks before you build its features.

Start with yourself

I'm just a single man. In the grand scheme of things, I'm yelling at the void.

If you can't fix the ecosystem, you must mitigate the risk. GitHub and modern tooling offer incredible security features: static analysis, reporting, bug bots—but the ultimate responsibility is on you.

You can't change the ecosystem, but you can change your projects. Mitigate, get ready for the worst-case scenario, and remain vigilant. Vet everything. Remain critical. Security is not an afterthought; it's the foundation. And you can't build a house with E2EE curtains if the foundation is made of unvetted, trivial dependency slop.

Or, alternatively, and I know you're gonna hate me for saying this, abandon the ecosystem that doesn't care about slop, and look for one that does.

End of article