Skip to content
Engineering

Security by Design: How Ephemeral Containers Keep Your Code Safe

Ovvoc team··6 min read

When you connect a dependency update tool to your repositories, you're trusting it with your source code. That trust has to be earned. Here's how Ovvoc's architecture ensures your code stays safe at every stage.

Why security is non-negotiable

Dependency update tools need access to your source code. They clone your repo, modify files, run your build, and execute your test suite. That's a lot of surface area. A compromised tool — or even a misconfigured one — can leak code, inject malicious changes, or expose secrets.

We designed Ovvoc's architecture around a single principle: minimize trust requirements. Every architectural decision reduces what you need to trust us with.

Ephemeral containers: created and destroyed per job

Every update job runs in its own Docker container. The container is created from a clean image at the start of the job and destroyed immediately after completion. There's no shared state between jobs, no persistent filesystem, no leftover artifacts.

This means:

  • A vulnerability in one customer's dependency can't affect another customer
  • Malicious postinstall scripts are contained to a single disposable environment
  • Even if a container is somehow compromised, it ceases to exist moments later

Network isolation during build and test

After dependencies are installed (which requires network access to the npm registry), Ovvoc cuts all outbound network access for the build and test stages. This prevents:

  • Exfiltration of source code or secrets during build/test
  • Malicious packages phoning home with your code
  • Unexpected network calls that could leak information

The build and test stages run in a completely air-gapped environment. If your code compiles and your tests pass without network access, the update is clean.

Short-lived tokens

Ovvoc uses GitHub App installation tokens that expire after each job. We never store long-lived credentials. The token is generated at the start of a job, used to clone the repo and create the PR, and expires shortly after. Even if a token were intercepted, it would be useless within minutes.

Zero code storage

Your source code exists only inside the ephemeral container for the duration of the job. We don't cache it. We don't log it. We don't store it in any database, object store, or file system. When the container is destroyed, your code is gone.

The only things we persist are metadata: which packages were updated, whether the build passed, the confidence score, and the failure report (if applicable). Never the code itself.

Self-hosted agent for enterprise

For organizations where code must never leave their infrastructure — even temporarily — Ovvoc offers a self-hosted agent. The agent runs on your own servers, behind your firewall, with your security policies. It communicates with Ovvoc's control plane only to receive job instructions and report results. Your code never touches our infrastructure.

This is the same agent that powers our hosted service, packaged for deployment in your environment.

The bottom line

Security isn't a feature we added after launch. It's the architecture itself. Ephemeral containers, network isolation, short-lived tokens, zero storage, and self-hosted deployment — each layer reduces what you need to trust.

Threat model

Designing a security architecture starts with understanding what you're defending against. Ovvoc's threat model covers the specific risks inherent to dependency update tools:

  • Malicious npm postinstall scripts — packages can execute arbitrary code during npm install. A compromised or typosquatted package could attempt to read environment variables, exfiltrate files, or install backdoors
  • Supply chain attacks — typosquatting (publishing express-sesion to catch typos), account takeover (compromising a maintainer's npm credentials), and dependency confusion (publishing internal package names to public registries)
  • Data exfiltration attempts — malicious code in build scripts or test suites that attempts to send your source code, API keys, or environment variables to external servers
  • Resource exhaustion — crypto mining in build scripts, fork bombs, or memory exhaustion attacks that could affect other customers or the host system
  • Filesystem escape attempts — container breakout exploits, symlink attacks, or path traversal that attempt to access the host filesystem or other containers

Each layer of our architecture addresses one or more of these threats. Defense in depth ensures that no single vulnerability can compromise the system.

Container lifecycle

Every update job follows a strict container lifecycle. Understanding this lifecycle helps explain why your code is safe at every stage:

  1. Create container from locked base image — the container uses a pinned, version-locked base image that we control. No package managers, no unnecessary tools, no attack surface beyond what's needed for the job
  2. Mount workspace as volume — the cloned repository is mounted into the container's workspace directory. The mount is scoped to a single directory with no access to the host filesystem
  3. Install dependencies with network accessnpm install requires network access to the npm registry. This is the only phase where outbound network is permitted, and it's restricted to registry domains
  4. Run update pipeline with no network — after installation, all network access is revoked. Build and test stages run in a completely air-gapped environment
  5. Extract results — build artifacts, test results, and job metadata are extracted from the container. Source code is never extracted — only pass/fail status and logs
  6. Destroy container and all data — the container is stopped, its filesystem is destroyed, and its network namespace is reclaimed. Nothing persists

Total lifecycle is typically 30–120 seconds depending on project size, number of dependencies, and test suite duration. The container exists only for the duration of the job.

Security hardening specifics

Beyond the basic container isolation, Ovvoc applies multiple layers of security hardening to every container:

  • Read-only root filesystem — the container's root filesystem is mounted read-only. Only the workspace directory and /tmp are writable, preventing system-level modifications
  • Dropped ALL Linux capabilities — Linux capabilities like NET_RAW, SYS_ADMIN, and MKNOD are all dropped. The container runs with the absolute minimum privilege level
  • No new privileges flag — the no-new-privileges security option prevents processes inside the container from gaining additional privileges through setuid binaries or capability escalation
  • Seccomp default profile — Docker's default seccomp profile blocks over 40 dangerous system calls including mount, reboot, and ptrace
  • Memory limit (512MB) — prevents memory exhaustion attacks. Most npm projects build and test well within this limit
  • CPU limit (1 core) — prevents CPU exhaustion and crypto mining from affecting other jobs or the host
  • PID limit (256) — prevents fork bombs by limiting the number of processes a container can spawn
  • No network access during build/test — all outbound network is disabled after dependency installation, preventing data exfiltration
  • tmpfs for /tmp — temporary files are stored in memory-backed tmpfs, ensuring they're destroyed when the container exits

How we compare to CI/CD security

Most teams run their dependency updates through CI/CD pipelines like GitHub Actions, GitLab CI, or Jenkins. While these tools are excellent for general-purpose CI, their security model wasn't designed for running untrusted code.

GitHub Actions runs jobs in shared VMs with full network access. Every step in a workflow can reach the internet, access environment secrets, and communicate with other services. A malicious postinstall script running in a GitHub Actions workflow can exfiltrate your GITHUB_TOKEN, access secrets stored in the repository, and phone home with your source code.

Ovvoc's containers are fully isolated: no network access during build/test, no access to secrets beyond the scoped installation token, no persistent storage, and no access to other customer data. Each job is a sealed environment that exists only for the duration of the update.

This doesn't mean GitHub Actions is insecure for general CI — it means that dependency updates, which inherently involve running third-party code, benefit from a stricter security model than general-purpose CI provides.

Compliance readiness

Ovvoc's architecture is designed with compliance frameworks in mind, particularly for organizations subject to SOC 2, ISO 27001, or similar standards:

  • SOC 2 Type II aligned — our security controls map directly to SOC 2 trust service criteria for security, availability, and confidentiality
  • Encryption at rest and in transit — all customer data (metadata only — never source code) is encrypted at rest using AES-256. All communication uses TLS 1.3
  • No persistent code storage — source code exists only in ephemeral containers. This simplifies data retention policies and eliminates an entire category of data breach risk
  • Audit logging — every operation is logged: container creation, job execution, API access, and authentication events. Logs are immutable and retained for compliance review
  • Self-hosted agent for enterprise — for organizations where regulatory requirements mandate that code never leave their infrastructure, the self-hosted agent ensures complete data sovereignty. The agent runs on your servers, behind your firewall, with your security policies

Want to learn more about our security model? See the full security details.

Stay up to date

Automate your dependency updates. Start with one repo.