---
title: Zero Dependencies
description: Fewer dependencies, smaller attack surface — why minimal imports produce more resilient agents
tags: [security, architecture, dependencies, supply-chain]
dependencies: [supply-chain, zero-infra, threat-model]
---

# Zero Dependencies

Every dependency is code you did not write, did not review, and cannot fully control. A zero-dependency default is a security posture, not an aesthetic preference.

## Principles

- Start from zero and justify every addition.
- Build It Yourself (BIY) for straightforward features.
- Depend carefully when the domain is hard to implement safely (cryptography, HTML sanitization).
- No runtime CDN fetches: vendor what you need, serve it from your own origin.
- No build step required: the source is the artifact.

## What zero-dependencies eliminates

Traditional web applications inherit risk from deep dependency trees. A typical `node_modules` folder contains hundreds of packages, each with install hooks, transitive dependencies, and implicit trust chains. Zero-dependency architecture eliminates:

- **Install-time code execution**: no `postinstall` scripts, no arbitrary shell commands on `npm install`.
- **Transitive dependency compromise**: no chain of packages where one compromised leaf poisons the tree.
- **Registry and CDN availability risk**: no runtime failure because a third-party host is down.
- **Unreviewed upgrades**: no automatic major-version bumps pulling in new code paths.
- **Build toolchain attack surface**: no webpack, babel, or bundler plugins that execute during build.

## What stays

Some problems are dangerous to reimplement. Acceptable dependencies are small, focused, auditable, and free of transitive imports:

| Library | Purpose | Why not BIY |
|---------|---------|-------------|
| TweetNaCl | Symmetric encryption (XSalsa20-Poly1305) | Cryptography must be correct; audited, zero-dependency |
| DOMPurify | HTML sanitization against XSS | Sanitization edge cases are extensive; battle-tested |

These are vendored into the repository as versioned, hashed files. No runtime fetch. No CDN. No transitive tree.

## Vendoring pattern

```
/js/vendor/
  tweetnacl-XX.min.js
  dompurify-YY.min.js
```

```html
<script src="/js/vendor/tweetnacl-XX.min.js"></script>
<script src="/js/vendor/dompurify-YY.min.js"></script>
```

Track expected hashes. Review every version update diff before replacing a vendored file.

## The security argument

Fewer dependencies means fewer trust decisions. Fewer trust decisions means a smaller attack surface. A static-file agent with five vendored libraries has a reviewable, auditable codebase. A typical React application with 1,200 transitive dependencies does not.

This is not about avoiding all external code. It is about making every piece of external code a deliberate, visible choice.

## For agents

1. Default to zero dependencies for new features
2. Implement UI components, state management, and application logic directly
3. Depend on libraries where incorrect implementation creates security risk — cryptography, HTML sanitization, complex parsers. Do not trust an LLM to hand-roll these correctly; generative code is especially weak at cryptographic primitives and subtle edge cases that libraries have been audited against
4. For UI-heavy projects, a framework like React is reasonable scaffolding — the trade-off between dependency weight and development speed depends on your chosen risk profile
5. Vendor all runtime dependencies into the repository
6. Verify hashes and review diffs on every dependency update
7. Treat dependency count as a security metric, not a productivity metric
