Security Considerations for the `dofs` Package in Cloudflare Computer

The dofs package implements defense-in-depth security through capability-based RPC access, path sanitization, SQLite prepared statements, blob integrity checks, and mount isolation—each vetted by authority verification before any storage mutation occurs.

The dofs package is the authoritative SQLite-backed storage layer that drives the Cloudflare Computer filesystem. Because it stores user data and mediates all filesystem operations, its security design centers on capability-based access control combined with multiple layers of validation. This article examines the specific security mechanisms implemented across the codebase, with direct references to source files and functions.

Capability-Based Access Control

All mutable operations—writes, renames, deletes, and blob uploads—are exposed exclusively through the RPC surface defined in capnweb. The Durable Object that owns a mount creates a provider stub that is handed to the client; this stub carries the sole capability to invoke the provider's methods.

In src/provider.ts, the Provider class exposes methods like writeFile, rename, and remove only to callers holding a valid stub reference. Without the stub, no client can reach the storage API, creating a foundational access control boundary.

// Example: creating a mount-specific provider (the capability)
// Only code that receives this stub may invoke storage operations
import { Provider } from '@cloudflare/dofs';

async function mountProvider(doFs: Provider) {
  // All operations below are authorized only because `doFs` is a capability
  await doFs.writeFile('/foo.txt', new Uint8Array([1, 2, 3]));
}

Authority Verification and Sync Security

Before any change is applied, the sync engine verifies that the mount remains authoritative for the target path. This prevents rogue or stale replicas from overwriting newer data.

The applyChanges function in src/sync/apply.ts contains explicit guards: if the mount has lost authority (for example, because another replica has taken over), the operation throws before any database mutation occurs. Source comments note this as "learns the mount stayed authoritative" and the authoritative on the mount guard.

// Example: sync apply respects authority
// `applyChanges` rejects if the mount is no longer authoritative
import { applyChanges } from '@cloudflare/dofs/sync';

await applyChanges(mountId, changesArray); // throws if not authoritative

The sync engine in src/sync/changes.ts additionally enforces revision-based conflict resolution: incoming changes are applied only when their revision is newer than the local state. Stale updates are silently dropped, preventing rollback attacks.

Path Sanitization and Traversal Protection

All filesystem calls route through the Path class in src/path.ts, which resolves relative components (.., .) and canonicalizes the result before any database lookup. Attempts to escape the mount root trigger InvalidPathError before any I/O occurs.

// Example: safe path handling—any escape attempt throws
import { Path } from '@cloudflare/dofs';

try {
  const p = new Path('/my-mount', '../../etc/passwd');
  // `p.normalized` becomes '/my-mount' and constructor throws InvalidPathError
} catch (e) {
  console.error('Blocked path traversal:', e);
}

This validation layer ensures that no operation can reference files outside its designated mount boundary, even if malicious paths are supplied.

Database Security and SQL Injection Mitigation

The storage layer in src/storage.ts uses prepared statements via the better-sqlite3 wrapper for every query. User-supplied strings are never interpolated directly into SQL, eliminating injection vectors entirely. All parameter binding is handled by the underlying SQLite driver.

The with-db.ts helper in src/fs/with-db.ts enforces per-mount database isolation: each mount receives its own SQLite file and dedicated Database handle. Even with a buggy path, operations cannot cross into another mount's database.

Blob Integrity and Resource Limits

Blob handling in src/fs/blobCache.ts implements size validation and cryptographic integrity:

  • Uploads are checked against configurable size limits
  • SHA-256 hashes are computed on write and verified on read
  • Tampered or corrupted blobs are rejected before reaching application code

Resource exhaustion is prevented through src/fs/gc.ts, which runs periodic garbage collection to prune orphaned blobs and enforce maximum storage quotas per mount.

Safe Error Handling

All low-level failures map to curated error types defined in src/errors.ts: InvalidPathError, PermissionDeniedError, NotFoundError, and others. These error objects avoid leaking internal stack traces, database state, or mount structure to callers, reducing information available to attackers.

Summary

Frequently Asked Questions

How does dofs prevent one user from accessing another user's files?

Each mount receives its own SQLite database file and isolated Database handle through src/fs/with-db.ts. The Path class in src/path.ts canonicalizes all paths relative to the mount root and rejects any traversal attempt with InvalidPathError. Cross-mount access is impossible at both the filesystem and database layers.

What protects against SQL injection in the dofs storage layer?

src/storage.ts uses prepared statements exclusively via the better-sqlite3 wrapper. All user input is bound as parameters, never concatenated into query strings. This approach eliminates SQL injection vectors by design.

How does dofs handle sync conflicts between multiple replicas?

The sync engine in src/sync/changes.ts compares revision timestamps and applies changes only when the incoming revision is newer. src/sync/apply.ts additionally verifies that the local mount remains authoritative before any mutation. Stale or unauthorized updates are rejected, preventing data rollback or split-brain scenarios.

What prevents blob data from being corrupted or tampered with?

src/fs/blobCache.ts computes SHA-256 hashes on blob upload and verifies them on every read. Size limits are enforced before storage allocation. Corrupted or oversized payloads trigger errors before reaching application code, ensuring data integrity throughout the storage lifecycle.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →