Security & isolation
Where and how your code runs — made verifiable.
Your CI runs on our infrastructure, and every job runs in its own hardware-virtualized micro-VM. This page describes exactly how that isolation works, how long a job’s environment lives, and how you can independently verify the image your code runs on — without a sales call or an NDA.
Last updated: 2026-09-27 · v1.6
The isolation model
Untrusted CI code — your build steps, and anything they spawn, including Docker-in-Docker — is contained by several independent layers. The micro-VM is the primary boundary; the other layers limit what a job can reach and make an attempted breakout visible. This is defense-in-depth, not “trust the container.”
| Layer | Mechanism | What it contains |
|---|---|---|
| Hardware-virtualized micro-VM | Each runner pod runs inside its own micro-VM with its own guest kernel, using Kata Containers. A micro-VM is a lightweight virtual machine — not a shared-kernel container. | The primary boundary. CI code — and its Docker-in-Docker — cannot reach the host kernel or any other job’s VM. |
| Network default-deny | The runner’s network is deny-by-default, enforced in the kernel with eBPF / Cilium. It cannot accept inbound connections or reach into the cluster: private IP ranges, the cloud-metadata endpoint, the control plane, and neighbouring pods are all blocked, except an internal pull-through cache for packages and images. Outbound reaches the public internet. | Lateral movement, cloud-metadata credential theft, and reaching internal services. |
| No cluster credentials | The runner holds no token to the orchestrator (Kubernetes API). | The foothold for privilege escalation — even with root inside the VM, there is no cluster credential to pivot with. |
| Workload privileges | As on GitHub-hosted runners, your job runs as the non-root runner user with passwordless sudo, so it has full root inside its own micro-VM — as does the Docker-in-Docker engine. That privilege ends at the VM boundary: no host devices, host namespaces or host mounts, and no cluster credentials. | Keeps root inside the job’s own VM, away from the host. |
| Node separation | Runners run on dedicated runner hosts, physically separate from the control plane, secrets, and platform data. | Blast radius: a compromised job is nowhere near the platform’s control plane or other tenants’ data. |
| Runtime threat detection | Hosts run eBPF / Tetragon runtime detection, watching for activity that would indicate an escape from a VM onto the host. | Turns an attempted breakout into an observable, recorded event rather than a silent one. |
We name the primitives and say what each is for; we do not publish the policies, allowlists, versions, or topology behind them. Components are kept current on a security floor — specific version numbers are deliberately not published, since a version maps to a known set of CVEs.
Ephemeral by design
A job’s environment does not outlive the job.
- One job, one fresh VM. Every job gets a newly created micro-VM. Ephemeral means it exists only for that job.
- Destroyed on completion. When the job finishes, the VM and everything in it — checked-out code, environment, any secrets that reached it — are destroyed.
- No reuse across customers. A VM is never handed from one job to the next. There is no warm environment from which a later job could inherit residual code, caches, or secrets (the shared pull-through cache holds only public packages and images).
The boundary of a job is the boundary of trust.
Supply chain you can verify
The image your code runs on is built in public CI and is independently verifiable — you don’t have to take our word for what’s inside it.
The badges link to the live attestations and Scorecard; the signature, provenance and SBOM are verifiable with the commands below.
Immutable images. Digests are immutable; tags are pointers: vYYYYMMDD and sha-<commit> can be re-pointed by a rebuild, and untagged digests are cleaned up over time — so pin vYYYYMMDD@sha256:. On our side, the runner fleet is pinned to an exact digest, and its signature and provenance are verified before each re-pin.
Every image built from main is signed with cosign keyless (Sigstore — Fulcio + Rekor, via GitHub Actions OIDC) and carries SLSA build provenance and a CycloneDX SBOM attestation. The signature is applied only after the published-by-digest artifact passes a trivy gate that blocks fixable HIGH/CRITICAL vulnerabilities in OS packages — so a valid signature also means the image passed the CVE gate. The image is rebuilt weekly with fresh apt patches; Renovate bumps the base and tools; runners move to a new digest after its signature is verified.
Image: ghcr.io/tempusbuild/runner-ubuntu-24.04 — date tags, no floating :latest. To see which image a job ran on, open Set up job → Runner Image → Version: vYYYYMMDD in its log. Work against the @sha256: digest, not a tag:
IMAGE=ghcr.io/tempusbuild/runner-ubuntu-24.04
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:vYYYYMMDD" --format '{{.Manifest.Digest}}')
1. Signature — binds the image to our build workflow and to GitHub’s OIDC issuer. Any other identity is not our build:
cosign verify \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"
2. Build provenance — a Sigstore-signed SLSA attestation, verified with the gh CLI:
gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner tempusbuild
3. SBOM (CycloneDX) — a cosign attestation on the same digest. The SBOM is too large for the transparency log, so it is TSA-timestamped (RFC3161) instead of logged to Rekor; verification therefore skips the Rekor lookup but still checks identity, signature, and the trusted timestamp:
cosign verify-attestation \
--type cyclonedx \
--insecure-ignore-tlog \
--use-signed-timestamps \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"
--insecure-ignore-tlog waives only the Rekor lookup; the signature, the signing identity, and the RFC3161 timestamp are still verified. The signature in step 1 is the cryptographic anchor; provenance and SBOM bind to the same digest.
The signature and provenance are recorded in the public Rekor transparency log (открывается в новой вкладке). The full walkthrough and our CVE policy (открывается в новой вкладке) are in the runner-images SECURITY.md; the build workflow (открывается в новой вкладке) and the whole repository are open at github.com/tempusbuild/runner-images (открывается в новой вкладке).
Data & tenancy
- Location. Compute runs on bare-metal servers in the EU (Hetzner, Finland); backups are stored in the EU.
- Encrypted secrets. Kubernetes secrets are encrypted at rest in the cluster datastore, and our operational credentials are encrypted with age (sops) and never committed to Git in plaintext.
- In transit. The dashboard and API are served over TLS (Let’s Encrypt), with HSTS enforced. Internal metrics and health endpoints are not exposed to the public internet.
- Your CI secrets are not ours to leak. We don’t receive or store them: GitHub delivers them directly into your job’s micro-VM, which is destroyed when the job ends.
- Just-in-time job credentials. A runner receives only a short-lived, per-job registration token. No long-lived platform credential sits on the runner.
- Tenant data. Platform data — job history, balances, ledger — is isolated per tenant, so one customer’s data is not reachable from another customer’s context.
- Retention & deletion. Billing records and the ledger are kept for the statutory period; job metadata for the life of the account. Sessions expire after 30 days of inactivity (90 days max). Account deletion and pseudonymisation of personal data on request; records required by law are retained, unlinked from your identity.
- Recoverable backups. The database is continuously backed up with point-in-time recovery and a 30-day retention window.
Compliance & assessments
We state what exists today and what is on the roadmap — and nothing we haven’t earned.
Available now
- Verifiable supply chain — signed images, SLSA provenance, and SBOMs you can check yourself (above).
- Open runner images — the execution environment is public and readable.
- Published vulnerability-disclosure policy (below).
- Public status page — website availability and incident history at status.tempus.build; dashboard and runner monitoring is being added.
On the roadmap
- Independent isolation assessment — a third-party penetration test of the isolation model.
- SOC 2 — we are working toward it.
We are not currently certified against SOC 2 or any equivalent. The claims on this page are the ones you can verify directly today. Assessment reports, once available, are shared under NDA:
Request a security report — there is no lead-capture form on this page.
Responsible disclosure
Found a vulnerability in the platform, the runner images, or the supply-chain pipeline? Report it responsibly:
- Email: security@tempus.build
- security.txt: tempus.build/.well-known/security.txt (RFC 9116)
- Runner images: privately via GitHub Security Advisories on tempusbuild/runner-images (открывается в новой вкладке)
Please don’t open a public issue for an unpatched vulnerability. We acknowledge receipt and keep you posted through triage and fix.
Subprocessors
We use a small number of third-party processors to run the service. Personal data is processed only as needed to deliver it.
| Subprocessor | Purpose | Location |
|---|---|---|
| Hetzner | Compute and backups | EU |
| GitHub | Source, identity (OAuth / GitHub App), CI secret delivery | US |
| Mailgun | Transactional email and notifications | EU |
| DodoPayments | Payment processing (merchant of record) | US |
| Website analytics (Google Analytics): cookieless aggregated signals before your choice; cookies only with consent | US | |
| Yandex | Website analytics (Yandex Metrica), only with your consent | RU |
| Sentry | Error monitoring: error traces with GitHub id/login; no email or IP | EU (Germany) |
| OpenRouter (→ Anthropic) | LLM inference for the cost advisor (enabled for all accounts) — receives aggregated cost metrics, repository/workflow names and the text of any question you ask; no source code, secrets or user identities | US |
This list is versioned; material changes are reflected here with the revision date above.