From 759c1176bbe4d74e58823c52761903c8bdc34a5e Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Mon, 29 Jun 2026 08:09:36 +0000 Subject: [PATCH 01/13] docs: make security triage visible --- .github/ISSUE_TEMPLATE/config.yml | 12 +++ .github/ISSUE_TEMPLATE/security-question.yml | 52 ++++++++++++ README.md | 21 ++++- SECURITY.md | 37 +++++++++ docs/security/README.md | 14 ++++ docs/security/security-best-practices.md | 15 ++++ docs/security/security-issue-triage.md | 53 ++++++++++++ docs/security/security-model.md | 16 +++- docs/tutorials/kms-build-configuration.md | 13 ++- docs/tutorials/kms-cvm-deployment.md | 7 +- sdk/curl/api.md | 10 ++- sdk/go/README.md | 86 +++++++++++--------- sdk/js/README.md | 36 ++++---- sdk/python/README.md | 15 +--- sdk/rust/README.md | 2 + 15 files changed, 304 insertions(+), 85 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/security-question.yml create mode 100644 SECURITY.md create mode 100644 docs/security/security-issue-triage.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..2c8cf0d65 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: © 2026 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +blank_issues_enabled: true +contact_links: + - name: Report an exploitable security vulnerability + url: https://github.com/Dstack-TEE/dstack/security/policy + about: Do not open a public issue. Use private disclosure for exploitable vulnerabilities. + - name: Check answered security reports + url: https://github.com/Dstack-TEE/dstack/blob/master/docs/security/security-issue-triage.md + about: Public status for answered, fixed, accepted, and roadmap security reports. diff --git a/.github/ISSUE_TEMPLATE/security-question.yml b/.github/ISSUE_TEMPLATE/security-question.yml new file mode 100644 index 000000000..45afdf973 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security-question.yml @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: © 2026 Phala Network +# +# SPDX-License-Identifier: Apache-2.0 + +name: Security docs question or prior finding +description: Ask about documented behavior or already-public findings. Do not report vulnerabilities here. +title: "Security docs: " +labels: ["question"] +body: + - type: markdown + attributes: + value: | + Do not use this form for exploitable vulnerabilities. Report exploitable issues privately through the repository security policy: + https://github.com/Dstack-TEE/dstack/security/policy + + Before filing, check the security issue triage page for answered reports: + https://github.com/Dstack-TEE/dstack/blob/master/docs/security/security-issue-triage.md + - type: textarea + id: concern + attributes: + label: Security docs question or prior finding + description: Describe the documented behavior, setting, or prior public report you want maintainers to evaluate. + placeholder: "Example: Does `auth_api.type = \"dev\"` affect production KMS deployments?" + validations: + required: true + - type: textarea + id: prior-art + attributes: + label: Prior reports or docs checked + description: Link any related issues, advisories, code locations, or docs you already checked. + placeholder: "Example: #608, docs/security/security-issue-triage.md" + validations: + required: true + - type: dropdown + id: impact + attributes: + label: Expected classification + description: Pick the closest public category. Maintainers may change it during triage. + options: + - Question about documented behavior + - Possible duplicate of an answered report + - Docs clarification + - Defense-in-depth hardening idea without an exploit claim + validations: + required: true + - type: checkboxes + id: disclosure + attributes: + label: Vulnerability disclosure + options: + - label: This is not an exploitable vulnerability report. If it may be exploitable, I will use the private security report channel. + required: true diff --git a/README.md b/README.md index 13205350b..c48f6909c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Original Contributors: Hang Yin, Kevin Wang, Andrew Miller -[Documentation](https://docs.phala.com/dstack) · [Examples](https://github.com/Dstack-TEE/dstack-examples) · [Community](https://t.me/+UO4bS4jflr45YmUx) +[Documentation](https://docs.phala.com/dstack) · [Security](./SECURITY.md) · [Examples](https://github.com/Dstack-TEE/dstack-examples) · [Community](https://t.me/+UO4bS4jflr45YmUx) @@ -89,6 +89,18 @@ Your container runs inside a Confidential VM, such as Intel TDX or AMD SEV-SNP, [Full security model →](./docs/security/security-model.md) +## Security and Trust + +dstack is security-critical infrastructure. Prior public security findings, accepted threat-model decisions, and production hardening guidance are documented publicly instead of being buried in issue threads. + +- [Security Overview](./docs/security/) - entry point for users, operators, researchers, and AI agents +- [Security Model](./docs/security/security-model.md) - threat model, trust boundaries, and verification checklist +- [Security Issue Triage](./docs/security/security-issue-triage.md) - public status for answered, fixed, accepted, and roadmap security reports +- [Security Best Practices](./docs/security/security-best-practices.md) - production settings and hardening guidance +- [Responsible Disclosure](./SECURITY.md) - how to report vulnerabilities + +Do not open GitHub issues for exploitable vulnerabilities. Use the private reporting channel in [SECURITY.md](./SECURITY.md). + ## SDKs Apps communicate with the guest agent via HTTP over `/var/run/dstack.sock`. Use the [HTTP API](./sdk/curl/api.md) directly with curl, or use a language SDK: @@ -125,10 +137,13 @@ Apps communicate with the guest agent via HTTP over `/var/run/dstack.sock`. Use - [Security Overview](./docs/security/) - Security documentation and responsible disclosure - [Security Model](./docs/security/security-model.md) - Threat model and trust boundaries +- [Security Issue Triage](./docs/security/security-issue-triage.md) - Public status for answered, fixed, accepted, and roadmap reports - [Security Best Practices](./docs/security/security-best-practices.md) - Production hardening - [Security Audit](./docs/security/dstack-audit.pdf) - Third-party audit by zkSecurity - [CVM Boundaries](./docs/security/cvm-boundaries.md) - Information exchange and isolation +Report exploitable vulnerabilities through the private channel in [SECURITY.md](./SECURITY.md), not public GitHub issues. + ## FAQ
@@ -180,7 +195,7 @@ Yes. dstack runs on supported TEE-capable servers, including Intel TDX-capable h - **GCP**: Intel TDX (Confidential VMs) - **AWS**: Nitro Enclaves (NSM attestation) -- **Bare metal**: Intel TDX (4th/5th Gen Xeon) and AMD SEV-SNP on supported dstack OS images +- **Bare metal**: Intel TDX (4th/5th Gen Xeon) and AMD SEV-SNP on supported dstack OS images. Intel TDX is the production path; AMD SEV-SNP is new and experimental. - **GPUs**: NVIDIA Confidential Computing (H100, Blackwell)
@@ -227,5 +242,3 @@ Logo and branding assets: [dstack-logo-kit](./docs/assets/dstack-logo-kit/) ## License Apache 2.0 - - diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..3bf252176 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,37 @@ +# Security + +dstack is security-critical infrastructure for confidential workloads. This page is the root entry point for private vulnerability reporting, threat-model documentation, and public status for already-addressed findings. + +## Report a vulnerability + +Please report exploitable vulnerabilities privately to security@phala.network. We will respond within 48 hours. + +Do not open GitHub issues for exploitable vulnerabilities. Public issues are for questions, documentation gaps, duplicate-prone prior findings, and hardening ideas that do not disclose an exploit path. + +Use private disclosure for issues that could expose secrets, bypass attestation or authorization, compromise KMS keys, weaken workload isolation, or enable unauthorized code or configuration changes in production deployments. + +## Public security documentation + +- [Security documentation index](./docs/security/) - start here for the full security docs map +- [Security model](./docs/security/security-model.md) - threat model, trust boundaries, and verification checklist +- [Security best practices](./docs/security/security-best-practices.md) - production hardening guidance +- [Security issue triage](./docs/security/security-issue-triage.md) - public status for answered, fixed, accepted, and roadmap reports +- [CVM boundaries](./docs/security/cvm-boundaries.md) - what crosses the CVM boundary and why +- [zkSecurity audit report](./docs/security/dstack-audit.pdf) - third-party audit + +## Before filing a public security question + +Check [Security Issue Triage](./docs/security/security-issue-triage.md) before opening a public security question. It records reports that were fixed, accepted by design, documented, or moved to roadmap work. + +For duplicate-prone findings, search for the exact setting or behavior: + +- `quote_enabled = false` +- `auth_api.type = "dev"` +- `gateway_app_id = "any"` +- `rpc.tls.mutual.mandatory = false` +- `ed25519` and `secp256k1` key derivation for the same path +- `RATLS` HKDF salt and key versioning + +## Production trust boundary + +Development settings are not production-safe merely because they are present in the codebase. Production deployments must rely on measured configuration, expected TEE measurements, authorization policy, and attestation verification. The documented security model is the source of truth for what dstack treats as a production guarantee. diff --git a/docs/security/README.md b/docs/security/README.md index bc82eded6..3258d154d 100644 --- a/docs/security/README.md +++ b/docs/security/README.md @@ -2,6 +2,13 @@ dstack security resources for auditors, researchers, and operators. +## Start Here + +- **Users and verifiers:** read the [Security Model](./security-model.md) to understand what dstack guarantees and what you must verify. +- **Operators:** read [Security Best Practices](./security-best-practices.md) before deploying production KMS, gateway, or VMM services. +- **Security researchers and AI agents:** check [Security Issue Triage](./security-issue-triage.md) before filing a public question about an already-known finding. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). +- **Maintainers:** use [Security Issue Triage](./security-issue-triage.md) to classify public reports and close issues once the maintainer position is clear. + ## Audit dstack has been audited by zkSecurity. See the [full audit report](./dstack-audit.pdf). @@ -10,8 +17,15 @@ dstack has been audited by zkSecurity. See the [full audit report](./dstack-audi - [Security Model](./security-model.md) - Threat model, trust boundaries, and verification checklist - [Security Best Practices](./security-best-practices.md) - Production hardening guide +- [Security Issue Triage](./security-issue-triage.md) - Public status for answered, fixed, accepted, and roadmap reports - [CVM Boundaries](./cvm-boundaries.md) - Information exchange and isolation details +## Already Answered Reports + +Some public security reports describe real hardening, some describe intentionally accepted threat-model decisions, and some are false positives under production configuration. The canonical list is [Security Issue Triage](./security-issue-triage.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. + ## Responsible Disclosure To report a security vulnerability, email security@phala.network. We will respond within 48 hours. + +Do not open GitHub issues for exploitable vulnerabilities. diff --git a/docs/security/security-best-practices.md b/docs/security/security-best-practices.md index e93ffb683..865c7f411 100644 --- a/docs/security/security-best-practices.md +++ b/docs/security/security-best-practices.md @@ -68,6 +68,21 @@ Example app-compose.json: **But keep in mind, even if you disable exposing app-compose.json, it is just hidden from the public API, the physical machine controller can still access it on the file system.** +## Do not use development trust settings in production + +Development settings are intentionally easy to audit, but they are not production-safe. A production deployment should satisfy all of the following: + +- KMS quote verification remains enabled. Do not deploy production KMS with `quote_enabled = false`. +- KMS authorization uses webhook/on-chain policy. Do not use `auth_api.type = "dev"` with real key material. +- The KMS contract pins a concrete gateway app id. Do not use `gateway_app_id = "any"` for production traffic. +- TEE quotes are evaluated by deployment policy, including TCB status and expected OS/application measurements. + +The KMS TLS listener may keep `rpc.tls.mutual.mandatory = false` because bootstrap endpoints need to be reachable before a client has an RA-TLS certificate. Sensitive KMS routes still require the client certificate and attestation evidence in application code before releasing keys or signing certificates. + +## Keep private material owner-only + +Secret-bearing files should be owner-only (`0600`) wherever possible, including app keys, decrypted env files, KMS root keys, gateway WireGuard/TLS keys, and ACME credentials. Preserve restrictive permissions when copying volumes, backing up `/etc/kms/certs`, or moving gateway and certbot state between hosts. Public issue [#606](https://github.com/Dstack-TEE/dstack/issues/606) tracks the remaining low-cost hardening work in dstack-managed file writes. + ## docker logs is public available by default Similarly, to facilitate App observability, docker logs are public by default. You can disable exposing docker logs by setting public_logs=false. diff --git a/docs/security/security-issue-triage.md b/docs/security/security-issue-triage.md new file mode 100644 index 000000000..6db5391e6 --- /dev/null +++ b/docs/security/security-issue-triage.md @@ -0,0 +1,53 @@ +# Security Issue Triage + +Security issues should not remain open after the maintainer position is clear. An open issue means one of two things: a fix is still required, or a concrete design/roadmap item is intentionally being tracked. Everything else should be closed with a final maintainer comment and a link to the code or documentation that records the decision. + +This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, duplicate-prone prior findings, or hardening ideas that do not disclose an exploit path. + +## Triage labels + +Use these categories when evaluating public security questions and already-public reports: + +| Category | Meaning | Expected issue state | +| --- | --- | --- | +| Real blocker | Confirmed vulnerability that can compromise production security under supported configuration | Keep open until fixed; close as completed when the fix lands | +| Needs hardening | Not a broken trust boundary, but a defense-in-depth improvement with no compatibility cost | Keep open only while the patch is pending; close as completed when merged | +| Fixed | The reported behavior has already been fixed or is fixed by the linked change | Close as completed | +| Docs-only | The behavior is intentional or lower severity, but the repo must say so clearly | Close after documentation is merged | +| Accepted by design | The report conflicts with the documented threat model or with an intentional compatibility constraint | Close as not planned, with the design rationale linked | + +When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad "security" issue open just to remember future work. + +## March 2026 security cluster + +The March cluster contained a mix of real hardening, compatibility decisions, and false positives. The current repo position is: + +| Issue | Classification | Maintainer action | +| --- | --- | --- | +| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is a valid defense-in-depth improvement with no expected compatibility cost | +| [#605](https://github.com/Dstack-TEE/dstack/issues/605) Identical raw key material across `ed25519` and `secp256k1` for the same path | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved; docs now state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | +| [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Accepted by design for dev/test deployments | `gateway_app_id` is KMS contract configuration and is publicly auditable; production deployments must not use `"any"` | +| [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Accepted by design for local/integration testing | Dev auth is measured runtime configuration, not a production mode; production must use webhook/on-chain authorization | +| [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Accepted by design for local development | The flag is measured in runtime configuration and should fail production attestation policy | +| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Docs-only for current architecture | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | +| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Design roadmap, not a near-term vulnerability | Static salt is acceptable with high-entropy KMS root material and explicit context; key versioning/rotation requires a broader compatibility design | + +Recommended GitHub cleanup for this cluster: + +- Keep #606 open until the `0600` hardening change lands, then close it as completed. +- Close #605, #561, #607, #608, and #609 with links to the relevant security docs and maintainer rationale. +- Keep a separate roadmap issue for KMS key versioning/rotation if it has an owner and migration plan; otherwise close #552 as not planned for the current KDF version. + +## Search terms for duplicate-prone findings + +Researchers and AI agents should search this page and linked issues before treating these as new vulnerabilities: + +- `quote_enabled = false` +- `auth_api.type = "dev"` +- `gateway_app_id = "any"` +- `rpc.tls.mutual.mandatory = false` +- `get_temp_ca_cert` +- `ed25519` and `secp256k1` with the same derivation path +- `RATLS` HKDF salt +- KMS key versioning and rotation +- app keys and decrypted env file permissions diff --git a/docs/security/security-model.md b/docs/security/security-model.md index fc5ad8475..d819e9050 100644 --- a/docs/security/security-model.md +++ b/docs/security/security-model.md @@ -8,7 +8,7 @@ This document helps you evaluate whether dstack's security model fits your needs dstack removes the need to trust infrastructure operators. The cloud provider cannot read your memory, modify your code, or access your secrets. Network attackers cannot intercept your traffic because TLS terminates inside the TEE with keys fully controlled by the TEE (Zero Trust HTTPS). Docker registries cannot serve malicious images because the TEE verifies SHA256 digests before pulling. -The only thing you must trust is **TEE hardware** (currently Intel TDX, with AMD SEV support planned). You trust that the TEE provides genuine memory encryption and that quotes are signed by real hardware. For GPU workloads, you also trust **NVIDIA GPU hardware** and NVIDIA's Remote Attestation Service (NRAS). These are hardware-level trust assumptions. +The only thing you must trust is **TEE hardware**. Intel TDX is the production path. AMD SEV-SNP is available where the selected dstack OS image and host support it, but it is new and experimental. You trust that the TEE provides genuine memory encryption and that quotes are signed by real hardware. For GPU workloads, you also trust **NVIDIA GPU hardware** and NVIDIA's Remote Attestation Service (NRAS). These are hardware-level trust assumptions. Everything else is verifiable. @@ -134,6 +134,20 @@ The one case dstack does not leave to downstream is a genuinely invalid TCB: `dc > **Future work:** this will be refactored toward a grace-period model, where an out-of-date TCB is accepted for a bounded window after a new TCB level is published rather than being a binary downstream decision. +### Development modes are auditable, not production-safe + +dstack keeps several development switches as runtime or on-chain configuration rather than Cargo feature flags. Examples include KMS `quote_enabled = false`, `auth_api.type = "dev"`, and KMS contract `gateway_app_id = "any"`. These settings exist for local development and integration tests, not for production deployments. + +This is intentional. Runtime configuration that affects the trust boundary is visible in attestation measurements or public contract state. Cargo feature gates are not automatically more auditable because feature unification can enable a feature through a dependency graph, and the resulting runtime behavior is not represented as a measured deployment setting. + +Production verifiers should reject deployments that use these development settings. Operators should treat them the same way they treat debug-mode TEE quotes: useful for testing, invalid for production trust. + +### KMS mTLS is route-enforced for sensitive operations + +The KMS Rocket TLS listener permits connections without a client certificate because some bootstrap and public metadata endpoints must be reachable before a client has an RA-TLS certificate. That listener setting is not the authorization boundary for key material. + +Sensitive KMS handlers enforce their own boundary: callers must present the expected client certificate and attestation evidence before key derivation, KMS key replication, or certificate signing succeeds. Public endpoints are limited to bootstrap, metadata, health, and metrics behavior documented for operators. + ## Limitations ### Attestation proves identity, not correctness diff --git a/docs/tutorials/kms-build-configuration.md b/docs/tutorials/kms-build-configuration.md index 502346879..9d27d3a84 100644 --- a/docs/tutorials/kms-build-configuration.md +++ b/docs/tutorials/kms-build-configuration.md @@ -186,6 +186,9 @@ certs = "/etc/kms/certs/rpc.crt" # Mutual TLS (mTLS) Configuration [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" +# Keep the TLS listener optional because bootstrap/public endpoints must be +# reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs still +# enforce client certificate and attestation checks in their handlers. mandatory = false # Core KMS Configuration @@ -221,7 +224,7 @@ EOF | `[rpc]` | `address` | RPC server bind address | | `[rpc]` | `port` | RPC server port (9100) | | `[core]` | `cert_dir` | Directory for certificates | -| `[core]` | `pccs_url` | Local PCCS via host bridge (`10.0.2.2`) for quote verification | +| `[core]` | `pccs_url` | PCCS endpoint for quote verification | | `[core.auth_api]` | `url` | Auth-eth webhook service URL | | `[core.onboard]` | `enabled` | Enable bootstrap/onboard mode | @@ -321,7 +324,8 @@ chmod 600 /etc/kms/auth-eth.env ### Verify configuration ```bash -cat /etc/kms/auth-eth.env +grep -E '^(HOST|PORT|KMS_CONTRACT_ADDR)=' /etc/kms/auth-eth.env +grep -q '^ETH_RPC_URL=.' /etc/kms/auth-eth.env && echo "ETH_RPC_URL is set" ``` ## Step 7: Create Docker Image for CVM Deployment @@ -465,6 +469,9 @@ certs = "/etc/kms/certs/rpc.crt" # Mutual TLS (mTLS) Configuration [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" +# Keep the TLS listener optional because bootstrap/public endpoints must be +# reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs still +# enforce client certificate and attestation checks in their handlers. mandatory = false # Core KMS Configuration @@ -621,7 +628,7 @@ cat /etc/kms/kms.toml | python3 -c "import sys, tomllib; tomllib.load(sys.stdin. ```bash # Source and verify environment source /etc/kms/auth-eth.env -echo "ETH_RPC_URL: ${ETH_RPC_URL:0:30}..." +test -n "$ETH_RPC_URL" && echo "ETH_RPC_URL is set" echo "KMS_CONTRACT_ADDR: $KMS_CONTRACT_ADDR" ``` diff --git a/docs/tutorials/kms-cvm-deployment.md b/docs/tutorials/kms-cvm-deployment.md index a133b3683..b3827f3aa 100644 --- a/docs/tutorials/kms-cvm-deployment.md +++ b/docs/tutorials/kms-cvm-deployment.md @@ -49,7 +49,7 @@ Before starting, ensure you have: > **Why SGX is required:** The KMS uses Intel SGX to generate TDX attestation quotes via the `local_key_provider`. SGX Auto MP Registration must be enabled in BIOS so your platform is registered with Intel's Provisioning Certification Service (PCS). Without this registration, KMS cannot generate valid attestation quotes, and bootstrap will fail. -> **Why local registry?** The KMS Docker image is cached in your [Local Docker Registry](/tutorial/local-docker-registry) for reliable, fast access from CVMs. The auth-eth service inside the container requires `ETH_RPC_URL` and `KMS_CONTRACT_ADDR` environment variables — these are passed via docker-compose, not baked into the image. +> **Why local registry?** The KMS Docker image is cached in your [Local Docker Registry](/tutorial/local-docker-registry) for reliable, fast access from CVMs. This deployment passes `ETH_RPC_URL` and `KMS_CONTRACT_ADDR` through docker-compose so you can change the RPC endpoint or contract address without rebuilding the image. ## What Gets Deployed @@ -167,6 +167,9 @@ configs: [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" + # Keep the TLS listener optional because bootstrap/public endpoints must be + # reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs + # still enforce client certificate and attestation checks in their handlers. mandatory = false [core] @@ -277,7 +280,7 @@ export DSTACK_VMM_AUTH_PASSWORD=$(cat ~/.dstack/secrets/vmm-auth-token) - `--image dstack-0.5.7`: Guest image from VMM images directory - `--port tcp:0.0.0.0:9100:9100`: Maps host port 9100 to CVM port 9100 on all interfaces -> **Why `0.0.0.0` and not `127.0.0.1`?** Gateway CVMs use QEMU user-mode networking and reach the host via its public IP. If KMS is bound to localhost only, gateway CVMs cannot connect. KMS authentication uses TDX attestation, not network isolation, so public accessibility is safe. +> **Why `0.0.0.0` and not `127.0.0.1`?** Gateway CVMs use QEMU user-mode networking and reach the host via its public IP. If KMS is bound to localhost only, gateway CVMs cannot connect. KMS authorization uses TDX attestation and auth policy, not loopback binding. Expose only the required KMS port and monitor it as a public service. > **Note:** Do NOT use `--secure-time` flag - it causes CVM to hang during boot waiting for time sync. diff --git a/sdk/curl/api.md b/sdk/curl/api.md index b05a6717b..8b864f75d 100644 --- a/sdk/curl/api.md +++ b/sdk/curl/api.md @@ -64,7 +64,7 @@ curl --unix-socket /var/run/dstack.sock -X POST \ ### 2. Get Key -Generates an ECDSA key using the k256 elliptic curve, derived from the application key, and returns both the key and its signature chain. Sutable for ETH key generation. +Generates a deterministic private key from the application key and returns both the key and its signature chain. Suitable for ETH key generation when using the default `secp256k1` algorithm. **Endpoint:** `/GetKey` @@ -72,9 +72,11 @@ Generates an ECDSA key using the k256 elliptic curve, derived from the applicati | Field | Type | Description | Example | |-------|------|-------------|----------| -| `path` | string | Path for the key | `"my/key/path"` | -| `purpose` | string | Purpose for the key. Can be any string. This is used in the signature chain. | `"signing"` | `"encryption"` | -| `algorithm` | string | Either `secp256k1` or `ed25519`. Defaults to `secp256k1` | `ed25519` | +| `path` | string | Path for the key. This is the domain separator for deterministic key material. | `"my/key/path"` | +| `purpose` | string | Purpose for the key. Can be any string. This is used in the signature chain and does not affect the private key bytes. | `"signing"` | +| `algorithm` | string | Either `secp256k1` or `ed25519`. Defaults to `secp256k1`. For compatibility, this selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. | `ed25519` | + +Use algorithm-specific paths, such as `wallet/ethereum` and `wallet/solana`, when independent keys are required across algorithms. **Example:** ```bash diff --git a/sdk/go/README.md b/sdk/go/README.md index 43815a563..96a661b5b 100644 --- a/sdk/go/README.md +++ b/sdk/go/README.md @@ -21,7 +21,7 @@ dstack applications consist of: ### SDK Capabilities -- **Key Derivation**: Deterministic secp256k1 key generation for blockchain and Web3 applications +- **Key Derivation**: Deterministic key derivation for blockchain and Web3 applications - **Remote Attestation**: TDX quote generation providing cryptographic proof of execution environment - **TLS Certificate Management**: Fresh certificate generation with optional RA-TLS support for secure connections - **Deployment Security**: Client-side encryption of sensitive environment variables ensuring secrets are only accessible to target TEE applications @@ -318,24 +318,16 @@ if err != nil { ```go import ( - "crypto/ed25519" "encoding/hex" - + "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) -keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "secp256k1") -if err != nil { - log.Fatal(err) -} - -// Standard keypair creation -keypair, err := dstack.ToSolanaKeypair(keyResult) +keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "ed25519") if err != nil { log.Fatal(err) } -// Enhanced security with SHA256 hashing (recommended) secureKeypair, err := dstack.ToSolanaKeypairSecure(keyResult) if err != nil { log.Fatal(err) @@ -365,8 +357,8 @@ The SDK provides end-to-end encryption capabilities for securely transmitting se import ( "encoding/hex" "fmt" - "time" - + "log" + "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) @@ -388,21 +380,28 @@ publicKeyBytes, _ := hex.DecodeString(publicKey) signatureBytes, _ := hex.DecodeString(signature) // Prefer timestamped verification to prevent replay attacks. -timestamp := uint64(time.Now().Unix()) // should come from KMS API response -trustedPubkey, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp( +timestamp := uint64(1710000000) // From the KMS API response, not local time +kmsIdentity, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp( publicKeyBytes, signatureBytes, "your-app-id-hex", timestamp, nil, // use default freshness policy (max age 300s) ) -if err != nil || trustedPubkey == nil { +if err != nil || kmsIdentity == nil { log.Fatal("KMS API provided untrusted encryption key") } -fmt.Println("Verified KMS public key:", hex.EncodeToString(trustedPubkey)) +expectedKMSIdentity := "03..." // From the DstackKms contract or deployment config +actualKMSIdentity := hex.EncodeToString(kmsIdentity) +if actualKMSIdentity != expectedKMSIdentity { + log.Fatalf("unexpected KMS identity: got %s", actualKMSIdentity) +} + +fmt.Println("Verified KMS public key:", actualKMSIdentity) -// Note: VerifyEnvEncryptPublicKey() is kept for legacy compatibility (without timestamp check). +// VerifyEnvEncryptPublicKey() is available only for explicit compatibility with +// older KMS builds. It does not provide timestamp replay protection. // 4. Encrypt environment variables for secure deployment encryptedData, err := dstack.EncryptEnvVars(envVars, publicKey) @@ -422,7 +421,7 @@ fmt.Println("Encrypted payload:", encryptedData) The SDK implements secure key derivation using: - **Deterministic Generation**: Keys are derived using HMAC-based Key Derivation Function (HKDF) -- **Application Isolation**: Each path produces unique keys, preventing cross-application access +- **Application Isolation**: Different `app_id` values derive different keys even with the same path - **Signature Verification**: All derived keys include cryptographic proof of origin - **TEE Protection**: Master keys never leave the secure enclave @@ -547,24 +546,27 @@ Retrieves comprehensive information about the TEE instance. - `EventLog`: Boot and runtime events - `AppCert`: Application certificate in PEM format -##### `GetKey(ctx context.Context, path string, purpose string) (*GetKeyResponse, error)` +##### `GetKey(ctx context.Context, path string, purpose string, algorithm string) (*GetKeyResponse, error)` -Derives a deterministic secp256k1/K256 private key for blockchain and Web3 applications. This is the primary method for obtaining cryptographic keys for wallets, signing, and other deterministic key scenarios. +Derives deterministic private key material for blockchain and Web3 applications. This is the primary method for obtaining cryptographic keys for wallets, signing, and other deterministic key scenarios. **Parameters:** - `path`: Unique identifier for key derivation (e.g., `"wallet/ethereum"`, `"signing/solana"`) -- `purpose`: Additional context for key usage (default: `""`) +- `purpose`: Included in the signature-chain message; does not affect the private key bytes +- `algorithm`: `"secp256k1"` (default behavior), `"k256"` (alias), or `"ed25519"` **Returns:** `GetKeyResponse` -- `Key`: 32-byte secp256k1 private key as hex string (suitable for Ethereum, Bitcoin, Solana, etc.) +- `Key`: 32-byte private key material as a hex string - `SignatureChain`: Array of cryptographic signatures proving key authenticity **Key Characteristics:** -- **Deterministic**: Same path + purpose always generates identical key +- **Deterministic**: Same path always generates identical raw key material for the same app - **Isolated**: Different paths produce cryptographically independent keys -- **Blockchain-Ready**: Compatible with secp256k1 curve (Ethereum, Bitcoin, Solana) +- **Blockchain-Ready**: Use `secp256k1` for Ethereum and Bitcoin-style signing; use `ed25519` with a Solana-specific path for independent Solana keys - **Verifiable**: Signature chain proves key was derived inside genuine TEE +For compatibility, `algorithm` selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. Use algorithm-specific paths when independent keys are required. + **Use Cases:** - Cryptocurrency wallets - Transaction signing @@ -575,8 +577,8 @@ Derives a deterministic secp256k1/K256 private key for blockchain and Web3 appli ```go // Examples of deterministic key derivation ethWallet, _ := client.GetKey(ctx, "wallet/ethereum", "mainnet", "secp256k1") -btcWallet, _ := client.GetKey(ctx, "wallet/bitcoin", "mainnet") -solWallet, _ := client.GetKey(ctx, "wallet/solana", "mainnet") +btcWallet, _ := client.GetKey(ctx, "wallet/bitcoin", "mainnet", "secp256k1") +solWallet, _ := client.GetKey(ctx, "wallet/solana", "mainnet", "ed25519") // Same path always returns same key key1, _ := client.GetKey(ctx, "my-app/signing", "", "secp256k1") @@ -695,7 +697,9 @@ Verify the authenticity of encryption public keys provided by KMS APIs: ```go import ( "encoding/hex" - "time" + "fmt" + "log" + "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) @@ -704,16 +708,20 @@ publicKey, _ := hex.DecodeString("e33a1832c6562067ff8f844a61e51ad051f1180b66ec25 signature, _ := hex.DecodeString("8542c49081fbf4e03f62034f13fbf70630bdf256a53032e38465a27c36fd6bed7a5e7111652004aef37f7fd92fbfc1285212c4ae6a6154203a48f5e16cad2cef00") appID := "0000000000000000000000000000000000000000" -timestamp := uint64(time.Now().Unix()) // should come from KMS API response +timestamp := uint64(1710000000) // From the KMS API response kmsIdentity, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp(publicKey, signature, appID, timestamp, nil) -if err == nil && kmsIdentity != nil { - fmt.Println("Trusted KMS identity:", hex.EncodeToString(kmsIdentity)) - // Safe to use the public key for encryption -} else { - fmt.Println("KMS signature verification failed") - // Potential man-in-the-middle attack +if err != nil || kmsIdentity == nil { + log.Fatal("KMS signature verification failed") } + +expectedKMSIdentity := "03..." // From the DstackKms contract or deployment config +actualKMSIdentity := hex.EncodeToString(kmsIdentity) +if actualKMSIdentity != expectedKMSIdentity { + log.Fatalf("unexpected KMS identity: got %s", actualKMSIdentity) +} + +fmt.Println("Trusted KMS identity:", actualKMSIdentity) ``` ## Security Best Practices @@ -734,9 +742,9 @@ if err == nil && kmsIdentity != nil { - Implement proper certificate validation 4. **Error Handling** - - Handle cryptographic operation failures gracefully + - Fail closed on security-critical cryptographic errors - Log security events for monitoring - - Implement fallback mechanisms where appropriate + - Avoid fallback behavior that weakens verification or key isolation ## Migration Guide @@ -744,7 +752,7 @@ if err == nil && kmsIdentity != nil { The legacy client mixed two different use cases that have now been properly separated: -1. **`GetKey()`**: Deterministic key derivation for Web3/blockchain (secp256k1) +1. **`GetKey()`**: Deterministic key derivation for Web3/blockchain keys 2. **`GetTlsKey()`**: Random TLS certificate generation for HTTPS/SSL ### From TappdClient to DstackClient @@ -783,7 +791,7 @@ client := dstack.NewDstackClient() keyResult, _ := client.DeriveKey(ctx, "wallet") // After: DstackClient methods -keyResult, _ := client.GetKey(ctx, "wallet", "ethereum") +keyResult, _ := client.GetKey(ctx, "wallet/ethereum", "ethereum", "secp256k1") // For TLS certificates // Before: DeriveKey with TLS options diff --git a/sdk/js/README.md b/sdk/js/README.md index ebd13de68..156d706d0 100644 --- a/sdk/js/README.md +++ b/sdk/js/README.md @@ -49,7 +49,7 @@ const client = new DstackClient('/run/dstack/dstack.sock') // custom path ### `getKey(path?, purpose?, algorithm?)` -Derive a deterministic key. Same `(app_id, path, purpose, algorithm)` always returns the same key; different apps deriving on the same path get different keys. +Derive a deterministic key. The same `(app_id, path)` returns the same raw key material; different apps deriving on the same path get different keys. ```typescript const eth = await client.getKey('wallet/ethereum') // secp256k1 (default) @@ -58,7 +58,7 @@ const sol = await client.getKey('wallet/solana', 'mainnet', 'ed25519') // ed25 Returns `{ key: Uint8Array, signature_chain: Uint8Array[] }`. The signature chain proves the key was derived inside a genuine TEE. -`algorithm`: `'secp256k1'` (default), `'k256'` (alias), or `'ed25519'`. ed25519 requires guest agent ≥ 0.5.7. +`purpose` is included in the signature-chain message and does not affect the private key bytes. `algorithm` selects how the derived 32-byte material is interpreted: `'secp256k1'` (default), `'k256'` (alias), or `'ed25519'`. It does not domain-separate the derivation, so use algorithm-specific paths such as `wallet/ethereum` and `wallet/solana` when those keys must be independent. ed25519 requires guest agent ≥ 0.5.7. ### `getTlsKey(options?)` @@ -208,7 +208,6 @@ The full deployment flow mirrors `vmm-cli.py`: fetch the env-encrypt public key ```typescript import { verifyEnvEncryptPublicKey, - verifyEnvEncryptPublicKeyLegacy, } from '@phala/dstack-sdk' import { encryptEnvVars, type EnvVar } from '@phala/dstack-sdk/encrypt-env-vars' @@ -220,27 +219,22 @@ const response = await fetch(`${kmsUrl}/prpc/GetAppEnvEncryptPubKey?json`, { const publicKey = Buffer.from(response.public_key, 'hex') -// Prefer v1 (timestamp-protected against replay) -let signer = response.signature_v1 - ? verifyEnvEncryptPublicKey( - publicKey, - Buffer.from(response.signature_v1, 'hex'), - appId, - BigInt(response.timestamp), - ) - : null - -// Fall back to legacy signature on older KMS -if (!signer && response.signature) { - signer = verifyEnvEncryptPublicKeyLegacy( - publicKey, - Buffer.from(response.signature, 'hex'), - appId, - ) +if (!response.signature_v1 || response.timestamp === undefined) { + throw new Error('KMS response missing timestamped signature') } +const signer = verifyEnvEncryptPublicKey( + publicKey, + Buffer.from(response.signature_v1, 'hex'), + appId, + BigInt(response.timestamp), +) + if (!signer) throw new Error('KMS signature did not verify') +const trustedSigners = new Set(['0x...']) // From the DstackKms contract or deployment config +if (!trustedSigners.has(signer)) throw new Error(`unexpected KMS signer: ${signer}`) + const envs: EnvVar[] = [ { key: 'DATABASE_URL', value: 'postgresql://…' }, { key: 'API_KEY', value: 'sk-test-1234' }, @@ -248,7 +242,7 @@ const envs: EnvVar[] = [ const encrypted = await encryptEnvVars(envs, response.public_key) ``` -Verify functions return the signer's compressed public key (hex) on success, or `null` on failure. Check the signer against your trusted-signer whitelist before encrypting. +Verify functions return the signer's compressed public key (hex) on success, or `null` on failure. `verifyEnvEncryptPublicKeyLegacy` is available only for deployments that explicitly support older KMS builds without `signature_v1`; it does not provide timestamp replay protection and should not be used for new deployments. ## Compatibility diff --git a/sdk/python/README.md b/sdk/python/README.md index 01ec56442..4093521d9 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -63,7 +63,7 @@ ed_key = client.get_key('signing/key', algorithm='ed25519') **Parameters:** - `path` (optional): Key derivation path. Defaults to `""` (root). - `purpose` (optional): Included in the signature chain message; does not affect the derived key. -- `algorithm` (optional): `'secp256k1'` (default) or `'ed25519'`. +- `algorithm` (optional): `'secp256k1'` (default) or `'ed25519'`. For compatibility, this selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. Use algorithm-specific paths when independent keys are required. **Returns:** `GetKeyResponse` - `key`: Hex-encoded private key @@ -260,7 +260,6 @@ The KMS returns a fresh X25519 public key (with a secp256k1 signature) that you from dstack_sdk import ( encrypt_env_vars, verify_env_encrypt_public_key, - verify_env_encrypt_public_key_legacy, EnvVar, ) @@ -272,15 +271,7 @@ signer = verify_env_encrypt_public_key( timestamp=timestamp, ) if signer is None: - # Fallback for older KMS builds that only emit the unprotected legacy - # signature. Vulnerable to replay; warn loudly if you must use it. - signer = verify_env_encrypt_public_key_legacy( - public_key=public_key_bytes, - signature=legacy_signature_bytes, - app_id=app_id_hex, - ) - if signer is None: - raise RuntimeError('invalid KMS env-encrypt public key') + raise RuntimeError('invalid KMS env-encrypt public key') # Always compare the recovered signer against a known-good KMS signer # address, obtained out-of-band from the DstackKms contract or your @@ -303,6 +294,8 @@ encrypted = await encrypt_env_vars(env_vars, public_key_hex) `verify_env_encrypt_public_key` returns the recovered compressed secp256k1 signer (`0x`-prefixed hex) on success, or `None` for any failure (bad length, expired/future timestamp, malformed `app_id`, invalid signature). The default `max_age_seconds` is 300; pass a larger value if your deployment workflow legitimately holds the response longer. +`verify_env_encrypt_public_key_legacy` remains available only for deployments that explicitly support older KMS builds without `signature_v1`. It does not provide timestamp replay protection and should not be used for new deployments. + ### Calculate Compose Hash ```python diff --git a/sdk/rust/README.md b/sdk/rust/README.md index cc5761b38..4fe1d282f 100644 --- a/sdk/rust/README.md +++ b/sdk/rust/README.md @@ -56,6 +56,8 @@ let testnet_key = client.get_key(Some("wallet/eth/testnet".to_string()), None).a - `path`: Key derivation path (determines the key) - `purpose` (optional): Included in signature chain message, does not affect the derived key +For compatibility, the key algorithm selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. Use algorithm-specific paths when independent keys are required. + **Returns:** `GetKeyResponse` - `key`: Hex-encoded private key - `signature_chain`: Signatures proving the key was derived in a genuine TEE From cb85f950dc9eea3bcd7c6404dc9694f4a56ff49a Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Mon, 29 Jun 2026 08:30:59 +0000 Subject: [PATCH 02/13] docs: address security docs review --- .github/ISSUE_TEMPLATE/config.yml | 12 ----- .github/ISSUE_TEMPLATE/security-question.yml | 52 -------------------- README.md | 18 ++----- SECURITY.md | 30 +++-------- docs/security/README.md | 8 +-- sdk/go/README.md | 26 +++++----- 6 files changed, 28 insertions(+), 118 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/security-question.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 2c8cf0d65..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: © 2026 Phala Network -# -# SPDX-License-Identifier: Apache-2.0 - -blank_issues_enabled: true -contact_links: - - name: Report an exploitable security vulnerability - url: https://github.com/Dstack-TEE/dstack/security/policy - about: Do not open a public issue. Use private disclosure for exploitable vulnerabilities. - - name: Check answered security reports - url: https://github.com/Dstack-TEE/dstack/blob/master/docs/security/security-issue-triage.md - about: Public status for answered, fixed, accepted, and roadmap security reports. diff --git a/.github/ISSUE_TEMPLATE/security-question.yml b/.github/ISSUE_TEMPLATE/security-question.yml deleted file mode 100644 index 45afdf973..000000000 --- a/.github/ISSUE_TEMPLATE/security-question.yml +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-FileCopyrightText: © 2026 Phala Network -# -# SPDX-License-Identifier: Apache-2.0 - -name: Security docs question or prior finding -description: Ask about documented behavior or already-public findings. Do not report vulnerabilities here. -title: "Security docs: " -labels: ["question"] -body: - - type: markdown - attributes: - value: | - Do not use this form for exploitable vulnerabilities. Report exploitable issues privately through the repository security policy: - https://github.com/Dstack-TEE/dstack/security/policy - - Before filing, check the security issue triage page for answered reports: - https://github.com/Dstack-TEE/dstack/blob/master/docs/security/security-issue-triage.md - - type: textarea - id: concern - attributes: - label: Security docs question or prior finding - description: Describe the documented behavior, setting, or prior public report you want maintainers to evaluate. - placeholder: "Example: Does `auth_api.type = \"dev\"` affect production KMS deployments?" - validations: - required: true - - type: textarea - id: prior-art - attributes: - label: Prior reports or docs checked - description: Link any related issues, advisories, code locations, or docs you already checked. - placeholder: "Example: #608, docs/security/security-issue-triage.md" - validations: - required: true - - type: dropdown - id: impact - attributes: - label: Expected classification - description: Pick the closest public category. Maintainers may change it during triage. - options: - - Question about documented behavior - - Possible duplicate of an answered report - - Docs clarification - - Defense-in-depth hardening idea without an exploit claim - validations: - required: true - - type: checkboxes - id: disclosure - attributes: - label: Vulnerability disclosure - options: - - label: This is not an exploitable vulnerability report. If it may be exploitable, I will use the private security report channel. - required: true diff --git a/README.md b/README.md index c48f6909c..a7ab583fe 100644 --- a/README.md +++ b/README.md @@ -91,15 +91,16 @@ Your container runs inside a Confidential VM, such as Intel TDX or AMD SEV-SNP, ## Security and Trust -dstack is security-critical infrastructure. Prior public security findings, accepted threat-model decisions, and production hardening guidance are documented publicly instead of being buried in issue threads. +Security docs are linked here so deployers and reviewers can quickly find the trust model, production guidance, audit, and the status of already-answered public findings. - [Security Overview](./docs/security/) - entry point for users, operators, researchers, and AI agents - [Security Model](./docs/security/security-model.md) - threat model, trust boundaries, and verification checklist - [Security Issue Triage](./docs/security/security-issue-triage.md) - public status for answered, fixed, accepted, and roadmap security reports - [Security Best Practices](./docs/security/security-best-practices.md) - production settings and hardening guidance -- [Responsible Disclosure](./SECURITY.md) - how to report vulnerabilities +- [Security Audit](./docs/security/dstack-audit.pdf) - third-party audit by zkSecurity +- [Report a Vulnerability](./SECURITY.md) - use GitHub's private security reporting path -Do not open GitHub issues for exploitable vulnerabilities. Use the private reporting channel in [SECURITY.md](./SECURITY.md). +Please do not disclose exploitable vulnerabilities in public GitHub issues. Use the private reporting path in [SECURITY.md](./SECURITY.md). ## SDKs @@ -133,17 +134,6 @@ Apps communicate with the guest agent via HTTP over `/var/run/dstack.sock`. Use - [Design Decisions](./docs/design-and-hardening-decisions.md) - Architecture rationale - [FAQ](./docs/faq.md) - Frequently asked questions -## Security - -- [Security Overview](./docs/security/) - Security documentation and responsible disclosure -- [Security Model](./docs/security/security-model.md) - Threat model and trust boundaries -- [Security Issue Triage](./docs/security/security-issue-triage.md) - Public status for answered, fixed, accepted, and roadmap reports -- [Security Best Practices](./docs/security/security-best-practices.md) - Production hardening -- [Security Audit](./docs/security/dstack-audit.pdf) - Third-party audit by zkSecurity -- [CVM Boundaries](./docs/security/cvm-boundaries.md) - Information exchange and isolation - -Report exploitable vulnerabilities through the private channel in [SECURITY.md](./SECURITY.md), not public GitHub issues. - ## FAQ
diff --git a/SECURITY.md b/SECURITY.md index 3bf252176..3342bd792 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,36 +1,20 @@ # Security -dstack is security-critical infrastructure for confidential workloads. This page is the root entry point for private vulnerability reporting, threat-model documentation, and public status for already-addressed findings. +Use this file for vulnerability reports. For the security model, production guidance, audit, and already-answered public findings, start with [Security Documentation](./docs/security/). ## Report a vulnerability -Please report exploitable vulnerabilities privately to security@phala.network. We will respond within 48 hours. +If you believe you found a vulnerability, please use GitHub's private security reporting features for this repository. If GitHub private reporting is unavailable, contact security@phala.network. -Do not open GitHub issues for exploitable vulnerabilities. Public issues are for questions, documentation gaps, duplicate-prone prior findings, and hardening ideas that do not disclose an exploit path. +Do not open public GitHub issues for exploitable vulnerabilities or details that could help exploit production deployments. -Use private disclosure for issues that could expose secrets, bypass attestation or authorization, compromise KMS keys, weaken workload isolation, or enable unauthorized code or configuration changes in production deployments. +Use private reporting for issues that could expose secrets, bypass attestation or authorization, compromise KMS keys, weaken workload isolation, or enable unauthorized code or configuration changes in production deployments. -## Public security documentation +## Public security questions -- [Security documentation index](./docs/security/) - start here for the full security docs map -- [Security model](./docs/security/security-model.md) - threat model, trust boundaries, and verification checklist -- [Security best practices](./docs/security/security-best-practices.md) - production hardening guidance -- [Security issue triage](./docs/security/security-issue-triage.md) - public status for answered, fixed, accepted, and roadmap reports -- [CVM boundaries](./docs/security/cvm-boundaries.md) - what crosses the CVM boundary and why -- [zkSecurity audit report](./docs/security/dstack-audit.pdf) - third-party audit +Use public issues only for questions about documented behavior, documentation gaps, already-public findings, or hardening ideas that do not include an exploit path. -## Before filing a public security question - -Check [Security Issue Triage](./docs/security/security-issue-triage.md) before opening a public security question. It records reports that were fixed, accepted by design, documented, or moved to roadmap work. - -For duplicate-prone findings, search for the exact setting or behavior: - -- `quote_enabled = false` -- `auth_api.type = "dev"` -- `gateway_app_id = "any"` -- `rpc.tls.mutual.mandatory = false` -- `ed25519` and `secp256k1` key derivation for the same path -- `RATLS` HKDF salt and key versioning +Before opening a public security question, check [Security Issue Triage](./docs/security/security-issue-triage.md). It records public findings that were fixed, accepted by design, documented, or moved to roadmap work. ## Production trust boundary diff --git a/docs/security/README.md b/docs/security/README.md index 3258d154d..978118fb7 100644 --- a/docs/security/README.md +++ b/docs/security/README.md @@ -6,7 +6,7 @@ dstack security resources for auditors, researchers, and operators. - **Users and verifiers:** read the [Security Model](./security-model.md) to understand what dstack guarantees and what you must verify. - **Operators:** read [Security Best Practices](./security-best-practices.md) before deploying production KMS, gateway, or VMM services. -- **Security researchers and AI agents:** check [Security Issue Triage](./security-issue-triage.md) before filing a public question about an already-known finding. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). +- **Security researchers and AI agents:** report exploitable vulnerabilities through the private path in [SECURITY.md](../../SECURITY.md). For already-public findings or docs questions, check [Security Issue Triage](./security-issue-triage.md) before opening a public issue. - **Maintainers:** use [Security Issue Triage](./security-issue-triage.md) to classify public reports and close issues once the maintainer position is clear. ## Audit @@ -22,10 +22,10 @@ dstack has been audited by zkSecurity. See the [full audit report](./dstack-audi ## Already Answered Reports -Some public security reports describe real hardening, some describe intentionally accepted threat-model decisions, and some are false positives under production configuration. The canonical list is [Security Issue Triage](./security-issue-triage.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. +Some public security reports describe real hardening work. Some describe behavior that is intentional for development or compatibility, and some are false positives under production configuration. The canonical list is [Security Issue Triage](./security-issue-triage.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. -## Responsible Disclosure +## Report Vulnerabilities -To report a security vulnerability, email security@phala.network. We will respond within 48 hours. +If you believe you found an exploitable vulnerability, use GitHub's private security reporting features as described in [SECURITY.md](../../SECURITY.md). If GitHub private reporting is unavailable, contact security@phala.network. Do not open GitHub issues for exploitable vulnerabilities. diff --git a/sdk/go/README.md b/sdk/go/README.md index 96a661b5b..227ddb400 100644 --- a/sdk/go/README.md +++ b/sdk/go/README.md @@ -21,7 +21,7 @@ dstack applications consist of: ### SDK Capabilities -- **Key Derivation**: Deterministic key derivation for blockchain and Web3 applications +- **Key Derivation**: Deterministic key derivation for wallets, signing, encryption, and other application-specific secrets - **Remote Attestation**: TDX quote generation providing cryptographic proof of execution environment - **TLS Certificate Management**: Fresh certificate generation with optional RA-TLS support for secure connections - **Deployment Security**: Client-side encryption of sensitive environment variables ensuring secrets are only accessible to target TEE applications @@ -98,12 +98,12 @@ func main() { fmt.Println("App Name:", info.AppName) fmt.Println("TCB Info:", info.TcbInfo) - // Derive deterministic keys for blockchain applications + // Derive deterministic keys for application-specific secrets walletKey, err := client.GetKey(ctx, "wallet/ethereum", "mainnet", "secp256k1") if err != nil { log.Fatal(err) } - + keyBytes, _ := walletKey.DecodeKey() fmt.Println("Derived key (32 bytes):", hex.EncodeToString(keyBytes)) // secp256k1 private key fmt.Println("Signature chain:", walletKey.SignatureChain) // Authenticity proof @@ -114,13 +114,13 @@ func main() { "timestamp": time.Now().Unix(), "user_id": "alice", } - + jsonData, _ := json.Marshal(applicationData) quote, err := client.GetQuote(ctx, jsonData) if err != nil { log.Fatal(err) } - + fmt.Println("TDX Quote:", quote.Quote) fmt.Println("Event Log:", quote.EventLog) @@ -548,7 +548,7 @@ Retrieves comprehensive information about the TEE instance. ##### `GetKey(ctx context.Context, path string, purpose string, algorithm string) (*GetKeyResponse, error)` -Derives deterministic private key material for blockchain and Web3 applications. This is the primary method for obtaining cryptographic keys for wallets, signing, and other deterministic key scenarios. +Derives deterministic private key material for wallets, signing, encryption, stable service identities, and other application-specific secrets. **Parameters:** - `path`: Unique identifier for key derivation (e.g., `"wallet/ethereum"`, `"signing/solana"`) @@ -568,10 +568,10 @@ Derives deterministic private key material for blockchain and Web3 applications. For compatibility, `algorithm` selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. Use algorithm-specific paths when independent keys are required. **Use Cases:** -- Cryptocurrency wallets -- Transaction signing -- DeFi protocol interactions -- NFT operations +- Stable service identity keys +- Application signing keys +- Encryption key seeds +- Cryptocurrency wallets and transaction signing - Any scenario requiring consistent, reproducible keys ```go @@ -752,7 +752,7 @@ fmt.Println("Trusted KMS identity:", actualKMSIdentity) The legacy client mixed two different use cases that have now been properly separated: -1. **`GetKey()`**: Deterministic key derivation for Web3/blockchain keys +1. **`GetKey()`**: Deterministic key derivation for application-specific secrets 2. **`GetTlsKey()`**: Random TLS certificate generation for HTTPS/SSL ### From TappdClient to DstackClient @@ -786,7 +786,7 @@ client := dstack.NewDstackClient() **Step 2: Update Method Calls** ```go -// For deterministic keys (most common) +// For deterministic application keys (most common) // Before: TappdClient methods keyResult, _ := client.DeriveKey(ctx, "wallet") @@ -813,7 +813,7 @@ tlsCert, _ := client.GetTlsKey(ctx, dstack.TlsKeyOptions{ - [ ] **Client Code Updates:** - [ ] Replace `tappd.NewTappdClient()` with `dstack.NewDstackClient()` - [ ] Replace `DeriveKey()` calls with appropriate method: - - [ ] `GetKey()` for Web3/blockchain keys (deterministic) + - [ ] `GetKey()` for deterministic application keys - [ ] `GetTlsKey()` for TLS certificates (random) - [ ] Replace `TdxQuote()` calls with `GetQuote()` - [ ] **SECURITY CRITICAL**: Update blockchain integration functions: From 0a03e574a2d155acd16ab05895003e8d9edf3eb7 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Mon, 29 Jun 2026 19:19:22 +0000 Subject: [PATCH 03/13] docs: link security reporting guidance --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 3342bd792..4a91fd2c7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ Use this file for vulnerability reports. For the security model, production guid ## Report a vulnerability -If you believe you found a vulnerability, please use GitHub's private security reporting features for this repository. If GitHub private reporting is unavailable, contact security@phala.network. +If you believe you found a vulnerability, please use [GitHub's private security reporting features](https://docs.github.com/en/code-security/how-tos/report-and-fix-vulnerabilities/report-privately) for this repository. If GitHub private reporting is unavailable, contact security@phala.network. Do not open public GitHub issues for exploitable vulnerabilities or details that could help exploit production deployments. @@ -18,4 +18,4 @@ Before opening a public security question, check [Security Issue Triage](./docs/ ## Production trust boundary -Development settings are not production-safe merely because they are present in the codebase. Production deployments must rely on measured configuration, expected TEE measurements, authorization policy, and attestation verification. The documented security model is the source of truth for what dstack treats as a production guarantee. +Development settings are not production-safe merely because they are present in the codebase. Production deployments must rely on measured configuration, expected TEE measurements, authorization policy, and attestation verification. The [Security Model](./docs/security/security-model.md#development-modes-are-auditable-not-production-safe) is the source of truth for what dstack treats as a production guarantee. From 50e49cb609eb1da2f19b318ae90a04515727934c Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Mon, 29 Jun 2026 20:32:30 +0000 Subject: [PATCH 04/13] docs: address security triage review --- docs/security/security-issue-triage.md | 14 -------------- docs/tutorials/kms-build-configuration.md | 3 +-- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/docs/security/security-issue-triage.md b/docs/security/security-issue-triage.md index 6db5391e6..2cbbd2dbe 100644 --- a/docs/security/security-issue-triage.md +++ b/docs/security/security-issue-triage.md @@ -37,17 +37,3 @@ Recommended GitHub cleanup for this cluster: - Keep #606 open until the `0600` hardening change lands, then close it as completed. - Close #605, #561, #607, #608, and #609 with links to the relevant security docs and maintainer rationale. - Keep a separate roadmap issue for KMS key versioning/rotation if it has an owner and migration plan; otherwise close #552 as not planned for the current KDF version. - -## Search terms for duplicate-prone findings - -Researchers and AI agents should search this page and linked issues before treating these as new vulnerabilities: - -- `quote_enabled = false` -- `auth_api.type = "dev"` -- `gateway_app_id = "any"` -- `rpc.tls.mutual.mandatory = false` -- `get_temp_ca_cert` -- `ed25519` and `secp256k1` with the same derivation path -- `RATLS` HKDF salt -- KMS key versioning and rotation -- app keys and decrypted env file permissions diff --git a/docs/tutorials/kms-build-configuration.md b/docs/tutorials/kms-build-configuration.md index 9d27d3a84..fef925a9c 100644 --- a/docs/tutorials/kms-build-configuration.md +++ b/docs/tutorials/kms-build-configuration.md @@ -324,8 +324,7 @@ chmod 600 /etc/kms/auth-eth.env ### Verify configuration ```bash -grep -E '^(HOST|PORT|KMS_CONTRACT_ADDR)=' /etc/kms/auth-eth.env -grep -q '^ETH_RPC_URL=.' /etc/kms/auth-eth.env && echo "ETH_RPC_URL is set" +cat /etc/kms/auth-eth.env ``` ## Step 7: Create Docker Image for CVM Deployment From 9ddc24040983ccd2f9409800fe3b39ca7bb7b2e4 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Mon, 29 Jun 2026 23:14:46 +0000 Subject: [PATCH 05/13] docs: expand security audit triage --- docs/security/security-issue-triage.md | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/security/security-issue-triage.md b/docs/security/security-issue-triage.md index 2cbbd2dbe..189a3c8dc 100644 --- a/docs/security/security-issue-triage.md +++ b/docs/security/security-issue-triage.md @@ -18,22 +18,37 @@ Use these categories when evaluating public security questions and already-publi When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad "security" issue open just to remember future work. -## March 2026 security cluster +## March 2026 audit cluster (#549-#609) -The March cluster contained a mix of real hardening, compatibility decisions, and false positives. The current repo position is: +The March audit cluster contained a mix of real fixes, hardening work, compatibility decisions, false positives, and public threat-model questions. Several implementation PRs in this number range fixed reports, and some issue state has not caught up with the maintainer position. + +Already closed as completed: [#550](https://github.com/Dstack-TEE/dstack/issues/550), [#551](https://github.com/Dstack-TEE/dstack/issues/551), [#553](https://github.com/Dstack-TEE/dstack/issues/553), [#558](https://github.com/Dstack-TEE/dstack/issues/558), [#565](https://github.com/Dstack-TEE/dstack/issues/565), and [#568](https://github.com/Dstack-TEE/dstack/issues/568). The sibling public security issues [#614](https://github.com/Dstack-TEE/dstack/issues/614), [#615](https://github.com/Dstack-TEE/dstack/issues/615), [#616](https://github.com/Dstack-TEE/dstack/issues/616), [#617](https://github.com/Dstack-TEE/dstack/issues/617), [#618](https://github.com/Dstack-TEE/dstack/issues/618), and [#619](https://github.com/Dstack-TEE/dstack/issues/619) are also closed as completed. | Issue | Classification | Maintainer action | | --- | --- | --- | -| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is a valid defense-in-depth improvement with no expected compatibility cost | +| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Close the original as not planned, or split zero-padding for the unset instance ID into a separate hardening issue if an owner wants it | +| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Design roadmap, not a near-term vulnerability | Static salt is acceptable with high-entropy KMS root material and explicit context; key versioning/rotation requires a broader compatibility design | +| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup; close as completed | +| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Accepted by design | The setup code validates and opens the same in-memory LUKS header. Close as not planned with the maintainer rationale | +| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Needs hardening | Keep open while removing transient command-line exposure for secret-bearing setup commands, or close only if the maintainer explicitly accepts the early-boot exposure in the documented threat model | +| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions; close as completed | +| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. Close as not planned after linking the threat-model rationale | +| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. Close as not planned unless the token format changes | +| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Docs-only for current architecture | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | +| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. Close the original with that rationale, or split a production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` into a hardening issue | +| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary; close as completed | +| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. Close as not planned after linking the bootstrap rationale | +| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size; close as completed | +| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation; close as completed | | [#605](https://github.com/Dstack-TEE/dstack/issues/605) Identical raw key material across `ed25519` and `secp256k1` for the same path | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved; docs now state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | +| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is a valid defense-in-depth improvement with no expected compatibility cost | | [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Accepted by design for dev/test deployments | `gateway_app_id` is KMS contract configuration and is publicly auditable; production deployments must not use `"any"` | | [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Accepted by design for local/integration testing | Dev auth is measured runtime configuration, not a production mode; production must use webhook/on-chain authorization | | [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Accepted by design for local development | The flag is measured in runtime configuration and should fail production attestation policy | -| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Docs-only for current architecture | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | -| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Design roadmap, not a near-term vulnerability | Static salt is acceptable with high-entropy KMS root material and explicit context; key versioning/rotation requires a broader compatibility design | Recommended GitHub cleanup for this cluster: -- Keep #606 open until the `0600` hardening change lands, then close it as completed. -- Close #605, #561, #607, #608, and #609 with links to the relevant security docs and maintainer rationale. -- Keep a separate roadmap issue for KMS key versioning/rotation if it has an owner and migration plan; otherwise close #552 as not planned for the current KDF version. +- Keep #556 and #606 open only while their hardening patches are pending, then close them as completed. +- Close #554, #557, #563, #566, and #567 as completed, with links to the fixing PRs. +- Close #549, #555, #559, #560, #561, #562, #564, #605, #607, #608, and #609 with links to the relevant security docs and maintainer rationale. +- Keep a separate roadmap issue for #552 key versioning/rotation if it has an owner and migration plan; otherwise close #552 as not planned for the current KDF version. From e321e3ea2f959591e75127f07d5eb5bb52134d51 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 00:13:18 +0000 Subject: [PATCH 06/13] docs: list public security issues --- docs/security/security-issue-triage.md | 89 ++++++++++++++++---------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/docs/security/security-issue-triage.md b/docs/security/security-issue-triage.md index 189a3c8dc..4137a26cd 100644 --- a/docs/security/security-issue-triage.md +++ b/docs/security/security-issue-triage.md @@ -1,10 +1,10 @@ # Security Issue Triage -Security issues should not remain open after the maintainer position is clear. An open issue means one of two things: a fix is still required, or a concrete design/roadmap item is intentionally being tracked. Everything else should be closed with a final maintainer comment and a link to the code or documentation that records the decision. +This page indexes public security reports, trust-boundary questions, and security-model roadmap issues that are already visible in GitHub issues. It exists so maintainers, researchers, operators, and AI agents can quickly see whether a public report is fixed, accepted by design, documentation-only, or still open. -This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, duplicate-prone prior findings, or hardening ideas that do not disclose an exploit path. +This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, already-public findings, or hardening ideas that do not disclose an exploit path. -## Triage labels +## Triage categories Use these categories when evaluating public security questions and already-public reports: @@ -15,40 +15,59 @@ Use these categories when evaluating public security questions and already-publi | Fixed | The reported behavior has already been fixed or is fixed by the linked change | Close as completed | | Docs-only | The behavior is intentional or lower severity, but the repo must say so clearly | Close after documentation is merged | | Accepted by design | The report conflicts with the documented threat model or with an intentional compatibility constraint | Close as not planned, with the design rationale linked | +| Roadmap | Security-relevant design work that needs an owner, migration plan, or compatibility plan | Keep open only while it remains an active roadmap item | When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad "security" issue open just to remember future work. -## March 2026 audit cluster (#549-#609) +## Public security issue table -The March audit cluster contained a mix of real fixes, hardening work, compatibility decisions, false positives, and public threat-model questions. Several implementation PRs in this number range fixed reports, and some issue state has not caught up with the maintainer position. +Status reflects GitHub issue state on 2026-06-30. Update this table whenever a listed issue is closed, reopened, split, or superseded. -Already closed as completed: [#550](https://github.com/Dstack-TEE/dstack/issues/550), [#551](https://github.com/Dstack-TEE/dstack/issues/551), [#553](https://github.com/Dstack-TEE/dstack/issues/553), [#558](https://github.com/Dstack-TEE/dstack/issues/558), [#565](https://github.com/Dstack-TEE/dstack/issues/565), and [#568](https://github.com/Dstack-TEE/dstack/issues/568). The sibling public security issues [#614](https://github.com/Dstack-TEE/dstack/issues/614), [#615](https://github.com/Dstack-TEE/dstack/issues/615), [#616](https://github.com/Dstack-TEE/dstack/issues/616), [#617](https://github.com/Dstack-TEE/dstack/issues/617), [#618](https://github.com/Dstack-TEE/dstack/issues/618), and [#619](https://github.com/Dstack-TEE/dstack/issues/619) are also closed as completed. - -| Issue | Classification | Maintainer action | -| --- | --- | --- | -| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Close the original as not planned, or split zero-padding for the unset instance ID into a separate hardening issue if an owner wants it | -| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Design roadmap, not a near-term vulnerability | Static salt is acceptable with high-entropy KMS root material and explicit context; key versioning/rotation requires a broader compatibility design | -| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup; close as completed | -| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Accepted by design | The setup code validates and opens the same in-memory LUKS header. Close as not planned with the maintainer rationale | -| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Needs hardening | Keep open while removing transient command-line exposure for secret-bearing setup commands, or close only if the maintainer explicitly accepts the early-boot exposure in the documented threat model | -| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions; close as completed | -| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. Close as not planned after linking the threat-model rationale | -| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. Close as not planned unless the token format changes | -| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Docs-only for current architecture | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | -| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. Close the original with that rationale, or split a production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` into a hardening issue | -| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary; close as completed | -| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. Close as not planned after linking the bootstrap rationale | -| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size; close as completed | -| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation; close as completed | -| [#605](https://github.com/Dstack-TEE/dstack/issues/605) Identical raw key material across `ed25519` and `secp256k1` for the same path | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved; docs now state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | -| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is a valid defense-in-depth improvement with no expected compatibility cost | -| [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Accepted by design for dev/test deployments | `gateway_app_id` is KMS contract configuration and is publicly auditable; production deployments must not use `"any"` | -| [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Accepted by design for local/integration testing | Dev auth is measured runtime configuration, not a production mode; production must use webhook/on-chain authorization | -| [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Accepted by design for local development | The flag is measured in runtime configuration and should fail production attestation policy | - -Recommended GitHub cleanup for this cluster: - -- Keep #556 and #606 open only while their hardening patches are pending, then close them as completed. -- Close #554, #557, #563, #566, and #567 as completed, with links to the fixing PRs. -- Close #549, #555, #559, #560, #561, #562, #564, #605, #607, #608, and #609 with links to the relevant security docs and maintainer rationale. -- Keep a separate roadmap issue for #552 key versioning/rotation if it has an owner and migration plan; otherwise close #552 as not planned for the current KDF version. +| Issue | Status | Category | Disposition | +| --- | --- | --- | --- | +| [#113](https://github.com/Dstack-TEE/dstack/issues/113) Alternative to RA-TLS | Open | Roadmap | Tracks possible application-level attestation or pre-registration approaches. This is design work, not a vulnerability report | +| [#114](https://github.com/Dstack-TEE/dstack/issues/114) On-chain logs for KMS replication | Open | Roadmap | Tracks auditability and transparency for KMS onboarding and replication events | +| [#115](https://github.com/Dstack-TEE/dstack/issues/115) Censorship resistance in the KMS | Open | Roadmap | Tracks how KMS instances should prove an up-to-date chain view after de-registration or policy changes | +| [#125](https://github.com/Dstack-TEE/dstack/issues/125) Requirements for deploying dstack OS on GCP | Open | Roadmap | Tracks cloud image packaging, app config transfer, and cloud measurement calculation. This is cloud trust plumbing, not an SNP-specific issue | +| [#318](https://github.com/Dstack-TEE/dstack/issues/318) Security advisory unavailable | Closed | Docs-only | Clarified that the linked advisory was private at the time and expected to become public later | +| [#330](https://github.com/Dstack-TEE/dstack/issues/330) Self-describing hash format for Intel DCAP `reportdata` | Open | Roadmap | Tracks a DIP for self-describing report data. This is format design, not a production vulnerability | +| [#411](https://github.com/Dstack-TEE/dstack/issues/411) Adopt RFC 8785 JCS for canonical compose hash calculation | Open | Roadmap | Tracks a possible future canonical hash scheme. Current raw-byte hashing is intentional and recorded in #550 | +| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Close the original as not planned, or split zero-padding for the unset instance ID into a separate hardening issue if an owner wants it | +| [#550](https://github.com/Dstack-TEE/dstack/issues/550) Compose hash computed on raw bytes, not canonicalized JSON | Closed | Accepted by design | dstack treats compose JSON as an opaque byte sequence. Any byte-level change is a different measured application configuration | +| [#551](https://github.com/Dstack-TEE/dstack/issues/551) Shell injection via `init_script` and `pre_launch_script` in compose | Closed | Accepted by design, docs-only | Scripts are application-owned code and are measured as part of app configuration. Verifiers must treat script contents as part of the application trust decision | +| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Roadmap | Static salt is acceptable with high-entropy KMS root material and explicit context. Key versioning and rotation require a broader compatibility design | +| [#553](https://github.com/Dstack-TEE/dstack/issues/553) `derive_dh_secret` hashes PKCS#8 DER | Closed | Fixed | [#603](https://github.com/Dstack-TEE/dstack/pull/603) stabilizes the P-256 private key encoding used for derivation | +| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup. Close as completed | +| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Accepted by design | The setup code validates and opens the same in-memory LUKS header. Close as not planned with the maintainer rationale | +| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Open | Needs hardening | Keep open while removing transient command-line exposure for secret-bearing setup commands, or close only if the maintainer explicitly accepts the early-boot exposure in the documented threat model | +| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Open | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions. Close as completed | +| [#558](https://github.com/Dstack-TEE/dstack/issues/558) Path traversal in KMS `remove_cache` | Closed | Fixed | [#601](https://github.com/Dstack-TEE/dstack/pull/601) validates cache paths before deletion | +| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. Close as not planned after linking the threat-model rationale | +| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. Close as not planned unless the token format changes | +| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Docs-only | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | +| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. Close the original with that rationale, or split a production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` into a hardening issue | +| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary. Close as completed | +| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. Close as not planned after linking the bootstrap rationale | +| [#565](https://github.com/Dstack-TEE/dstack/issues/565) Infinite loop in `wait_for_generation_change` | Closed | Fixed | [#596](https://github.com/Dstack-TEE/dstack/pull/596) bounds the ConfigFS generation wait loop | +| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Open | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size. Close as completed | +| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Open | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation. Close as completed | +| [#568](https://github.com/Dstack-TEE/dstack/issues/568) Webhook URL leaked via `println!` in production code | Closed | Fixed | Fixed before the issue was triaged by removing the unsafe log output in `79b8b8d2` | +| [#605](https://github.com/Dstack-TEE/dstack/issues/605) Guest agent derives identical key material for `ed25519` and `secp256k1` | Open | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved. Docs state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | +| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Open | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is valid defense-in-depth work with no expected compatibility cost | +| [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Open | Accepted by design for dev/test deployments | `gateway_app_id` is KMS contract configuration and is publicly auditable. Production deployments must not use `"any"` | +| [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Open | Accepted by design for local/integration testing | Dev auth is measured runtime configuration, not a production mode. Production must use webhook/on-chain authorization | +| [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Open | Accepted by design for local development | The flag is measured in runtime configuration and should fail production attestation policy | +| [#610](https://github.com/Dstack-TEE/dstack/issues/610) Unauthenticated bootstrap endpoint can overwrite root keys | Closed | Accepted by design | The bootstrap endpoint does not accept caller-supplied root key material. Root keys are generated server-side, and the operator chooses which result to publish | +| [#611](https://github.com/Dstack-TEE/dstack/issues/611) Unauthenticated `/finish` endpoint can shut down KMS onboard service | Closed | Accepted by design | The onboard service is a short-lived setup flow. Premature shutdown causes operator retry, not persistent compromise or data loss | +| [#612](https://github.com/Dstack-TEE/dstack/issues/612) Gateway `register_cvm` prefers stale `app_info` over live attestation | Closed | Accepted by design | Cert-embedded `app_info` is extracted from attestation and signed by KMS. Preferring it avoids redundant extraction and is not a trust bypass | +| [#613](https://github.com/Dstack-TEE/dstack/issues/613) 10-year default certificate validity undermines attestation freshness | Closed | Accepted by design | RA-TLS certificates embed attestation evidence and verifiers validate that evidence during connection handling. Freshness policy belongs in verifier policy, not only certificate expiry | +| [#614](https://github.com/Dstack-TEE/dstack/issues/614) VMM `no_tee` flag allows launching VMs without TDX protection | Closed | Accepted by design for dev/test deployments | `no_tee` VMs cannot produce valid TDX quotes and cannot join the production trust chain unless other development-only checks are also disabled | +| [#615](https://github.com/Dstack-TEE/dstack/issues/615) Host-supplied `sys_config` not measured but influences security-critical behavior | Closed | Accepted by design | Network endpoints are not trust anchors. KMS, gateway, and PCCS trust decisions rely on cryptographic verification, not host-supplied URLs | +| [#616](https://github.com/Dstack-TEE/dstack/issues/616) Host-controlled Docker registry mirror enables image substitution attacks | Closed | Accepted by design | Registry mirrors are untrusted transport. Digest-pinned image references and measured compose configuration protect against substitution | +| [#617](https://github.com/Dstack-TEE/dstack/issues/617) Guest agent exposes raw private keys to all local processes | Closed | Accepted by design | dstack treats a CVM as one application trust domain. It does not provide per-container key isolation inside the same measured application | +| [#618](https://github.com/Dstack-TEE/dstack/issues/618) Disk encryption disableable via kernel cmdline, not measured in RTMR | Closed | Accepted by design | The kernel command line is measured into RTMR2, so changing `dstack.storage_encrypted=false` changes attestation evidence | +| [#619](https://github.com/Dstack-TEE/dstack/issues/619) KMS `get_temp_ca_cert` returns temp CA private key without authentication | Closed | Duplicate | The report duplicates the private advisory response for the temp CA bootstrap flow | +| [#713](https://github.com/Dstack-TEE/dstack/issues/713) AMD SEV-SNP support tracking | Open | Roadmap | Tracks remaining work before AMD SEV-SNP can be called supported. SNP remains experimental and opt-in until the tracker is complete | +| [#744](https://github.com/Dstack-TEE/dstack/issues/744) Track AMD SEV-SNP support gap on GCP | Closed | Roadmap consolidation | Closed after clarifying that cloud deployment plumbing belongs in #125 and SNP support status belongs in #713 | +| [#745](https://github.com/Dstack-TEE/dstack/issues/745) `secure_time: true` cannot sync because guest chrony lacks NTS | Open | Real blocker | Tracks a secure-time boot failure. The fix is in [meta-dstack#76](https://github.com/Dstack-TEE/meta-dstack/pull/76) | +| [#746](https://github.com/Dstack-TEE/dstack/issues/746) Harden AMD SEV-SNP KDS collateral fetch | Open | Needs hardening | Tracks async client, timeout, and caching hardening for SNP KDS collateral fetch. Verification remains fail-closed | From 844232d8164565f97abdd61549c21d1e27add706 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 00:23:35 +0000 Subject: [PATCH 07/13] docs: split public security reports --- README.md | 2 +- SECURITY.md | 2 +- docs/security/README.md | 8 +-- ...e-triage.md => public-security-reports.md} | 49 ++++++++++++------- 4 files changed, 36 insertions(+), 25 deletions(-) rename docs/security/{security-issue-triage.md => public-security-reports.md} (78%) diff --git a/README.md b/README.md index a7ab583fe..a77b42fc3 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Security docs are linked here so deployers and reviewers can quickly find the tr - [Security Overview](./docs/security/) - entry point for users, operators, researchers, and AI agents - [Security Model](./docs/security/security-model.md) - threat model, trust boundaries, and verification checklist -- [Security Issue Triage](./docs/security/security-issue-triage.md) - public status for answered, fixed, accepted, and roadmap security reports +- [Public Security Reports](./docs/security/public-security-reports.md) - public status for security reports and related hardening work - [Security Best Practices](./docs/security/security-best-practices.md) - production settings and hardening guidance - [Security Audit](./docs/security/dstack-audit.pdf) - third-party audit by zkSecurity - [Report a Vulnerability](./SECURITY.md) - use GitHub's private security reporting path diff --git a/SECURITY.md b/SECURITY.md index 4a91fd2c7..c4cbe0e3a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -14,7 +14,7 @@ Use private reporting for issues that could expose secrets, bypass attestation o Use public issues only for questions about documented behavior, documentation gaps, already-public findings, or hardening ideas that do not include an exploit path. -Before opening a public security question, check [Security Issue Triage](./docs/security/security-issue-triage.md). It records public findings that were fixed, accepted by design, documented, or moved to roadmap work. +Before opening a public security question, check [Public Security Reports](./docs/security/public-security-reports.md). It records public reports that were fixed, accepted by design, documented, or split into related hardening and roadmap work. ## Production trust boundary diff --git a/docs/security/README.md b/docs/security/README.md index 978118fb7..d7485dd64 100644 --- a/docs/security/README.md +++ b/docs/security/README.md @@ -6,8 +6,8 @@ dstack security resources for auditors, researchers, and operators. - **Users and verifiers:** read the [Security Model](./security-model.md) to understand what dstack guarantees and what you must verify. - **Operators:** read [Security Best Practices](./security-best-practices.md) before deploying production KMS, gateway, or VMM services. -- **Security researchers and AI agents:** report exploitable vulnerabilities through the private path in [SECURITY.md](../../SECURITY.md). For already-public findings or docs questions, check [Security Issue Triage](./security-issue-triage.md) before opening a public issue. -- **Maintainers:** use [Security Issue Triage](./security-issue-triage.md) to classify public reports and close issues once the maintainer position is clear. +- **Security researchers and AI agents:** report exploitable vulnerabilities through the private path in [SECURITY.md](../../SECURITY.md). For already-public findings or docs questions, check [Public Security Reports](./public-security-reports.md) before opening a public issue. +- **Maintainers:** use [Public Security Reports](./public-security-reports.md) to classify public reports and close issues once the maintainer position is clear. ## Audit @@ -17,12 +17,12 @@ dstack has been audited by zkSecurity. See the [full audit report](./dstack-audi - [Security Model](./security-model.md) - Threat model, trust boundaries, and verification checklist - [Security Best Practices](./security-best-practices.md) - Production hardening guide -- [Security Issue Triage](./security-issue-triage.md) - Public status for answered, fixed, accepted, and roadmap reports +- [Public Security Reports](./public-security-reports.md) - Public status for security reports and related hardening work - [CVM Boundaries](./cvm-boundaries.md) - Information exchange and isolation details ## Already Answered Reports -Some public security reports describe real hardening work. Some describe behavior that is intentional for development or compatibility, and some are false positives under production configuration. The canonical list is [Security Issue Triage](./security-issue-triage.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. +Some public security reports describe real hardening work. Some describe behavior that is intentional for development or compatibility, and some are false positives under production configuration. The canonical list is [Public Security Reports](./public-security-reports.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. ## Report Vulnerabilities diff --git a/docs/security/security-issue-triage.md b/docs/security/public-security-reports.md similarity index 78% rename from docs/security/security-issue-triage.md rename to docs/security/public-security-reports.md index 4137a26cd..b1e194575 100644 --- a/docs/security/security-issue-triage.md +++ b/docs/security/public-security-reports.md @@ -1,12 +1,16 @@ -# Security Issue Triage +# Public Security Reports -This page indexes public security reports, trust-boundary questions, and security-model roadmap issues that are already visible in GitHub issues. It exists so maintainers, researchers, operators, and AI agents can quickly see whether a public report is fixed, accepted by design, documentation-only, or still open. +This page lists public GitHub issues that were filed as security reports or public mirrors of private advisories. It records the maintainer disposition so researchers, operators, and AI agents can tell whether a report is fixed, accepted by design, documentation-only, duplicate, or still open. + +This page also separates related security roadmap and hardening trackers from the report table. Those items matter for the security model, but they are not vulnerability reports and should not be read as CVE-style findings. This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, already-public findings, or hardening ideas that do not disclose an exploit path. -## Triage categories +Status reflects GitHub issue state on 2026-06-30. Update this page whenever a listed issue is closed, reopened, split, or superseded. + +## Report categories -Use these categories when evaluating public security questions and already-public reports: +Use these categories when evaluating public security reports and already-public findings: | Category | Meaning | Expected issue state | | --- | --- | --- | @@ -15,27 +19,20 @@ Use these categories when evaluating public security questions and already-publi | Fixed | The reported behavior has already been fixed or is fixed by the linked change | Close as completed | | Docs-only | The behavior is intentional or lower severity, but the repo must say so clearly | Close after documentation is merged | | Accepted by design | The report conflicts with the documented threat model or with an intentional compatibility constraint | Close as not planned, with the design rationale linked | -| Roadmap | Security-relevant design work that needs an owner, migration plan, or compatibility plan | Keep open only while it remains an active roadmap item | +| Duplicate | The report repeats another public issue or private advisory response | Close with a link to the canonical response | -When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad "security" issue open just to remember future work. +When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad security issue open just to remember future work. -## Public security issue table +## Public reports and findings -Status reflects GitHub issue state on 2026-06-30. Update this table whenever a listed issue is closed, reopened, split, or superseded. +These issues were filed as concrete vulnerability reports, security audit findings, or public mirrors of private advisories. Some were valid fixes. Some were accepted threat-model decisions or false positives under supported production configuration. | Issue | Status | Category | Disposition | | --- | --- | --- | --- | -| [#113](https://github.com/Dstack-TEE/dstack/issues/113) Alternative to RA-TLS | Open | Roadmap | Tracks possible application-level attestation or pre-registration approaches. This is design work, not a vulnerability report | -| [#114](https://github.com/Dstack-TEE/dstack/issues/114) On-chain logs for KMS replication | Open | Roadmap | Tracks auditability and transparency for KMS onboarding and replication events | -| [#115](https://github.com/Dstack-TEE/dstack/issues/115) Censorship resistance in the KMS | Open | Roadmap | Tracks how KMS instances should prove an up-to-date chain view after de-registration or policy changes | -| [#125](https://github.com/Dstack-TEE/dstack/issues/125) Requirements for deploying dstack OS on GCP | Open | Roadmap | Tracks cloud image packaging, app config transfer, and cloud measurement calculation. This is cloud trust plumbing, not an SNP-specific issue | -| [#318](https://github.com/Dstack-TEE/dstack/issues/318) Security advisory unavailable | Closed | Docs-only | Clarified that the linked advisory was private at the time and expected to become public later | -| [#330](https://github.com/Dstack-TEE/dstack/issues/330) Self-describing hash format for Intel DCAP `reportdata` | Open | Roadmap | Tracks a DIP for self-describing report data. This is format design, not a production vulnerability | -| [#411](https://github.com/Dstack-TEE/dstack/issues/411) Adopt RFC 8785 JCS for canonical compose hash calculation | Open | Roadmap | Tracks a possible future canonical hash scheme. Current raw-byte hashing is intentional and recorded in #550 | | [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Close the original as not planned, or split zero-padding for the unset instance ID into a separate hardening issue if an owner wants it | | [#550](https://github.com/Dstack-TEE/dstack/issues/550) Compose hash computed on raw bytes, not canonicalized JSON | Closed | Accepted by design | dstack treats compose JSON as an opaque byte sequence. Any byte-level change is a different measured application configuration | | [#551](https://github.com/Dstack-TEE/dstack/issues/551) Shell injection via `init_script` and `pre_launch_script` in compose | Closed | Accepted by design, docs-only | Scripts are application-owned code and are measured as part of app configuration. Verifiers must treat script contents as part of the application trust decision | -| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Roadmap | Static salt is acceptable with high-entropy KMS root material and explicit context. Key versioning and rotation require a broader compatibility design | +| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Docs-only, roadmap follow-up | Static salt is acceptable with high-entropy KMS root material and explicit context. Key versioning and rotation require a broader compatibility design | | [#553](https://github.com/Dstack-TEE/dstack/issues/553) `derive_dh_secret` hashes PKCS#8 DER | Closed | Fixed | [#603](https://github.com/Dstack-TEE/dstack/pull/603) stabilizes the P-256 private key encoding used for derivation | | [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup. Close as completed | | [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Accepted by design | The setup code validates and opens the same in-memory LUKS header. Close as not planned with the maintainer rationale | @@ -67,7 +64,21 @@ Status reflects GitHub issue state on 2026-06-30. Update this table whenever a l | [#617](https://github.com/Dstack-TEE/dstack/issues/617) Guest agent exposes raw private keys to all local processes | Closed | Accepted by design | dstack treats a CVM as one application trust domain. It does not provide per-container key isolation inside the same measured application | | [#618](https://github.com/Dstack-TEE/dstack/issues/618) Disk encryption disableable via kernel cmdline, not measured in RTMR | Closed | Accepted by design | The kernel command line is measured into RTMR2, so changing `dstack.storage_encrypted=false` changes attestation evidence | | [#619](https://github.com/Dstack-TEE/dstack/issues/619) KMS `get_temp_ca_cert` returns temp CA private key without authentication | Closed | Duplicate | The report duplicates the private advisory response for the temp CA bootstrap flow | -| [#713](https://github.com/Dstack-TEE/dstack/issues/713) AMD SEV-SNP support tracking | Open | Roadmap | Tracks remaining work before AMD SEV-SNP can be called supported. SNP remains experimental and opt-in until the tracker is complete | + +## Related security roadmap and hardening + +These issues affect security architecture, future verification behavior, operational hardening, or security documentation. They are intentionally separated from the report table because they are not vulnerability reports. + +| Issue | Status | Type | Scope | +| --- | --- | --- | --- | +| [#113](https://github.com/Dstack-TEE/dstack/issues/113) Alternative to RA-TLS | Open | Architecture roadmap | Tracks possible application-level attestation or pre-registration approaches | +| [#114](https://github.com/Dstack-TEE/dstack/issues/114) On-chain logs for KMS replication | Open | Auditability roadmap | Tracks transparency for KMS onboarding and replication events | +| [#115](https://github.com/Dstack-TEE/dstack/issues/115) Censorship resistance in the KMS | Open | Governance roadmap | Tracks how KMS instances should prove an up-to-date chain view after de-registration or policy changes | +| [#125](https://github.com/Dstack-TEE/dstack/issues/125) Requirements for deploying dstack OS on GCP | Open | Cloud trust plumbing | Tracks cloud image packaging, app config transfer, and cloud measurement calculation | +| [#318](https://github.com/Dstack-TEE/dstack/issues/318) Security advisory unavailable | Closed | Security process | Clarified that the linked advisory was private at the time and expected to become public later | +| [#330](https://github.com/Dstack-TEE/dstack/issues/330) Self-describing hash format for Intel DCAP `reportdata` | Open | Format roadmap | Tracks a DIP for self-describing report data | +| [#411](https://github.com/Dstack-TEE/dstack/issues/411) Adopt RFC 8785 JCS for canonical compose hash calculation | Open | Measurement roadmap | Tracks a possible future canonical hash scheme. Current raw-byte hashing is intentional and recorded in #550 | +| [#713](https://github.com/Dstack-TEE/dstack/issues/713) AMD SEV-SNP support tracking | Open | Platform roadmap | Tracks remaining work before AMD SEV-SNP can be called supported. SNP remains experimental and opt-in until the tracker is complete | | [#744](https://github.com/Dstack-TEE/dstack/issues/744) Track AMD SEV-SNP support gap on GCP | Closed | Roadmap consolidation | Closed after clarifying that cloud deployment plumbing belongs in #125 and SNP support status belongs in #713 | -| [#745](https://github.com/Dstack-TEE/dstack/issues/745) `secure_time: true` cannot sync because guest chrony lacks NTS | Open | Real blocker | Tracks a secure-time boot failure. The fix is in [meta-dstack#76](https://github.com/Dstack-TEE/meta-dstack/pull/76) | -| [#746](https://github.com/Dstack-TEE/dstack/issues/746) Harden AMD SEV-SNP KDS collateral fetch | Open | Needs hardening | Tracks async client, timeout, and caching hardening for SNP KDS collateral fetch. Verification remains fail-closed | +| [#745](https://github.com/Dstack-TEE/dstack/issues/745) `secure_time: true` cannot sync because guest chrony lacks NTS | Open | Security feature bug | Tracks a secure-time boot failure. The fix is in [meta-dstack#76](https://github.com/Dstack-TEE/meta-dstack/pull/76) | +| [#746](https://github.com/Dstack-TEE/dstack/issues/746) Harden AMD SEV-SNP KDS collateral fetch | Open | Availability hardening | Tracks async client, timeout, and caching hardening for SNP KDS collateral fetch. Verification remains fail-closed | From c4408a27165a834237f9814631ea5556281f4384 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 00:27:01 +0000 Subject: [PATCH 08/13] docs: trim trivial security issue entries --- docs/security/public-security-reports.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/security/public-security-reports.md b/docs/security/public-security-reports.md index b1e194575..40c238a38 100644 --- a/docs/security/public-security-reports.md +++ b/docs/security/public-security-reports.md @@ -8,6 +8,8 @@ This page is not a vulnerability reporting channel. Report exploitable vulnerabi Status reflects GitHub issue state on 2026-06-30. Update this page whenever a listed issue is closed, reopened, split, or superseded. +This page intentionally excludes support requests, process questions, roadmap consolidation issues, and general feature requests that only mention security-related terms in passing. + ## Report categories Use these categories when evaluating public security reports and already-public findings: @@ -75,10 +77,8 @@ These issues affect security architecture, future verification behavior, operati | [#114](https://github.com/Dstack-TEE/dstack/issues/114) On-chain logs for KMS replication | Open | Auditability roadmap | Tracks transparency for KMS onboarding and replication events | | [#115](https://github.com/Dstack-TEE/dstack/issues/115) Censorship resistance in the KMS | Open | Governance roadmap | Tracks how KMS instances should prove an up-to-date chain view after de-registration or policy changes | | [#125](https://github.com/Dstack-TEE/dstack/issues/125) Requirements for deploying dstack OS on GCP | Open | Cloud trust plumbing | Tracks cloud image packaging, app config transfer, and cloud measurement calculation | -| [#318](https://github.com/Dstack-TEE/dstack/issues/318) Security advisory unavailable | Closed | Security process | Clarified that the linked advisory was private at the time and expected to become public later | | [#330](https://github.com/Dstack-TEE/dstack/issues/330) Self-describing hash format for Intel DCAP `reportdata` | Open | Format roadmap | Tracks a DIP for self-describing report data | | [#411](https://github.com/Dstack-TEE/dstack/issues/411) Adopt RFC 8785 JCS for canonical compose hash calculation | Open | Measurement roadmap | Tracks a possible future canonical hash scheme. Current raw-byte hashing is intentional and recorded in #550 | | [#713](https://github.com/Dstack-TEE/dstack/issues/713) AMD SEV-SNP support tracking | Open | Platform roadmap | Tracks remaining work before AMD SEV-SNP can be called supported. SNP remains experimental and opt-in until the tracker is complete | -| [#744](https://github.com/Dstack-TEE/dstack/issues/744) Track AMD SEV-SNP support gap on GCP | Closed | Roadmap consolidation | Closed after clarifying that cloud deployment plumbing belongs in #125 and SNP support status belongs in #713 | | [#745](https://github.com/Dstack-TEE/dstack/issues/745) `secure_time: true` cannot sync because guest chrony lacks NTS | Open | Security feature bug | Tracks a secure-time boot failure. The fix is in [meta-dstack#76](https://github.com/Dstack-TEE/meta-dstack/pull/76) | | [#746](https://github.com/Dstack-TEE/dstack/issues/746) Harden AMD SEV-SNP KDS collateral fetch | Open | Availability hardening | Tracks async client, timeout, and caching hardening for SNP KDS collateral fetch. Verification remains fail-closed | From 61ca9f9da666469d86296c5eb3cf5468f6524805 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 01:08:01 +0000 Subject: [PATCH 09/13] docs: tighten security docs index --- SECURITY.md | 2 +- docs/security/README.md | 34 +++++------------ docs/security/public-security-reports.md | 48 ++++++++++++------------ 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c4cbe0e3a..fb28c40a2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -14,7 +14,7 @@ Use private reporting for issues that could expose secrets, bypass attestation o Use public issues only for questions about documented behavior, documentation gaps, already-public findings, or hardening ideas that do not include an exploit path. -Before opening a public security question, check [Public Security Reports](./docs/security/public-security-reports.md). It records public reports that were fixed, accepted by design, documented, or split into related hardening and roadmap work. +Before opening a public security question, check [Public Security Reports](./docs/security/public-security-reports.md). It records public report status and related hardening or roadmap work. ## Production trust boundary diff --git a/docs/security/README.md b/docs/security/README.md index d7485dd64..4086f2f79 100644 --- a/docs/security/README.md +++ b/docs/security/README.md @@ -1,31 +1,15 @@ # Security Documentation -dstack security resources for auditors, researchers, and operators. +Use these resources to understand dstack's trust model, production requirements, audit history, and public security report status. -## Start Here +## Resources -- **Users and verifiers:** read the [Security Model](./security-model.md) to understand what dstack guarantees and what you must verify. -- **Operators:** read [Security Best Practices](./security-best-practices.md) before deploying production KMS, gateway, or VMM services. -- **Security researchers and AI agents:** report exploitable vulnerabilities through the private path in [SECURITY.md](../../SECURITY.md). For already-public findings or docs questions, check [Public Security Reports](./public-security-reports.md) before opening a public issue. -- **Maintainers:** use [Public Security Reports](./public-security-reports.md) to classify public reports and close issues once the maintainer position is clear. +- [Security Model](./security-model.md) - threat model, trust boundaries, and verifier checklist +- [Security Best Practices](./security-best-practices.md) - production hardening for KMS, gateway, and VMM deployments +- [Security Audit](./dstack-audit.pdf) - zkSecurity audit report +- [Public Security Reports](./public-security-reports.md) - status of already-public reports and findings +- [CVM Boundaries](./cvm-boundaries.md) - data exchanged across the CVM, host, KMS, and gateway -## Audit +## Report a Vulnerability -dstack has been audited by zkSecurity. See the [full audit report](./dstack-audit.pdf). - -## Documentation - -- [Security Model](./security-model.md) - Threat model, trust boundaries, and verification checklist -- [Security Best Practices](./security-best-practices.md) - Production hardening guide -- [Public Security Reports](./public-security-reports.md) - Public status for security reports and related hardening work -- [CVM Boundaries](./cvm-boundaries.md) - Information exchange and isolation details - -## Already Answered Reports - -Some public security reports describe real hardening work. Some describe behavior that is intentional for development or compatibility, and some are false positives under production configuration. The canonical list is [Public Security Reports](./public-security-reports.md). Search that page by issue number, component, or exact setting name before treating an old report as unresolved. - -## Report Vulnerabilities - -If you believe you found an exploitable vulnerability, use GitHub's private security reporting features as described in [SECURITY.md](../../SECURITY.md). If GitHub private reporting is unavailable, contact security@phala.network. - -Do not open GitHub issues for exploitable vulnerabilities. +Do not disclose exploitable vulnerabilities in public GitHub issues. Use the private reporting path in [SECURITY.md](../../SECURITY.md). If GitHub private reporting is unavailable, contact security@phala.network. diff --git a/docs/security/public-security-reports.md b/docs/security/public-security-reports.md index 40c238a38..3930e56db 100644 --- a/docs/security/public-security-reports.md +++ b/docs/security/public-security-reports.md @@ -1,29 +1,29 @@ # Public Security Reports -This page lists public GitHub issues that were filed as security reports or public mirrors of private advisories. It records the maintainer disposition so researchers, operators, and AI agents can tell whether a report is fixed, accepted by design, documentation-only, duplicate, or still open. +This page lists public GitHub issues that were filed as security reports or public mirrors of private advisories. It records the project position so readers can tell whether a report is fixed, accepted by design, documentation-only, duplicate, or still open. This page also separates related security roadmap and hardening trackers from the report table. Those items matter for the security model, but they are not vulnerability reports and should not be read as CVE-style findings. This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, already-public findings, or hardening ideas that do not disclose an exploit path. -Status reflects GitHub issue state on 2026-06-30. Update this page whenever a listed issue is closed, reopened, split, or superseded. +Status reflects GitHub issue state on 2026-06-30. This page intentionally excludes support requests, process questions, roadmap consolidation issues, and general feature requests that only mention security-related terms in passing. ## Report categories -Use these categories when evaluating public security reports and already-public findings: +Use these categories when reading public security reports and already-public findings: -| Category | Meaning | Expected issue state | -| --- | --- | --- | -| Real blocker | Confirmed vulnerability that can compromise production security under supported configuration | Keep open until fixed; close as completed when the fix lands | -| Needs hardening | Not a broken trust boundary, but a defense-in-depth improvement with no compatibility cost | Keep open only while the patch is pending; close as completed when merged | -| Fixed | The reported behavior has already been fixed or is fixed by the linked change | Close as completed | -| Docs-only | The behavior is intentional or lower severity, but the repo must say so clearly | Close after documentation is merged | -| Accepted by design | The report conflicts with the documented threat model or with an intentional compatibility constraint | Close as not planned, with the design rationale linked | -| Duplicate | The report repeats another public issue or private advisory response | Close with a link to the canonical response | +| Category | Meaning | +| --- | --- | +| Real blocker | Confirmed vulnerability that can compromise production security under supported configuration | +| Needs hardening | Defense-in-depth improvement that does not change the production trust model | +| Fixed | The reported behavior has been fixed or is fixed by the linked change | +| Docs-only | The behavior is intentional or lower severity, but public documentation should make it clear | +| Accepted by design | The report conflicts with the documented threat model or an intentional compatibility constraint | +| Duplicate | The report repeats another public issue or private advisory response | -When a report mixes several claims, split the actionable work into separate issues before closing the original. Do not leave a broad security issue open just to remember future work. +Rows that mention follow-up work describe the public project status, not a vulnerability disclosure path. ## Public reports and findings @@ -31,25 +31,25 @@ These issues were filed as concrete vulnerability reports, security audit findin | Issue | Status | Category | Disposition | | --- | --- | --- | --- | -| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Close the original as not planned, or split zero-padding for the unset instance ID into a separate hardening issue if an owner wants it | +| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Zero-padding for the unset instance ID is optional hardening | | [#550](https://github.com/Dstack-TEE/dstack/issues/550) Compose hash computed on raw bytes, not canonicalized JSON | Closed | Accepted by design | dstack treats compose JSON as an opaque byte sequence. Any byte-level change is a different measured application configuration | | [#551](https://github.com/Dstack-TEE/dstack/issues/551) Shell injection via `init_script` and `pre_launch_script` in compose | Closed | Accepted by design, docs-only | Scripts are application-owned code and are measured as part of app configuration. Verifiers must treat script contents as part of the application trust decision | | [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Docs-only, roadmap follow-up | Static salt is acceptable with high-entropy KMS root material and explicit context. Key versioning and rotation require a broader compatibility design | | [#553](https://github.com/Dstack-TEE/dstack/issues/553) `derive_dh_secret` hashes PKCS#8 DER | Closed | Fixed | [#603](https://github.com/Dstack-TEE/dstack/pull/603) stabilizes the P-256 private key encoding used for derivation | -| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup. Close as completed | -| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Accepted by design | The setup code validates and opens the same in-memory LUKS header. Close as not planned with the maintainer rationale | -| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Open | Needs hardening | Keep open while removing transient command-line exposure for secret-bearing setup commands, or close only if the maintainer explicitly accepts the early-boot exposure in the documented threat model | -| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Open | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions. Close as completed | +| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup | +| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Accepted by design | The setup code validates and opens the same in-memory LUKS header | +| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Open | Needs hardening | Tracks removal of transient command-line exposure for secret-bearing setup commands | +| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Open | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions | | [#558](https://github.com/Dstack-TEE/dstack/issues/558) Path traversal in KMS `remove_cache` | Closed | Fixed | [#601](https://github.com/Dstack-TEE/dstack/pull/601) validates cache paths before deletion | -| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. Close as not planned after linking the threat-model rationale | -| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. Close as not planned unless the token format changes | +| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements | +| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token | | [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Docs-only | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | -| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. Close the original with that rationale, or split a production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` into a hardening issue | -| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary. Close as completed | -| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. Close as not planned after linking the bootstrap rationale | +| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. A production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` remains possible hardening | +| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary | +| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret | | [#565](https://github.com/Dstack-TEE/dstack/issues/565) Infinite loop in `wait_for_generation_change` | Closed | Fixed | [#596](https://github.com/Dstack-TEE/dstack/pull/596) bounds the ConfigFS generation wait loop | -| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Open | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size. Close as completed | -| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Open | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation. Close as completed | +| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Open | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size | +| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Open | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation | | [#568](https://github.com/Dstack-TEE/dstack/issues/568) Webhook URL leaked via `println!` in production code | Closed | Fixed | Fixed before the issue was triaged by removing the unsafe log output in `79b8b8d2` | | [#605](https://github.com/Dstack-TEE/dstack/issues/605) Guest agent derives identical key material for `ed25519` and `secp256k1` | Open | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved. Docs state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | | [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Open | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is valid defense-in-depth work with no expected compatibility cost | From 576a31e887b0d1b5c4fa7b2870921f9f712b6a60 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 02:23:43 +0000 Subject: [PATCH 10/13] docs: shorten public security reports intro --- docs/security/public-security-reports.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/security/public-security-reports.md b/docs/security/public-security-reports.md index 3930e56db..bb7cc2e24 100644 --- a/docs/security/public-security-reports.md +++ b/docs/security/public-security-reports.md @@ -1,14 +1,10 @@ # Public Security Reports -This page lists public GitHub issues that were filed as security reports or public mirrors of private advisories. It records the project position so readers can tell whether a report is fixed, accepted by design, documentation-only, duplicate, or still open. +This page tracks public GitHub issues filed as security reports or mirrors of private advisories. It shows whether each report is fixed, accepted by design, documentation-only, duplicate, or still open. -This page also separates related security roadmap and hardening trackers from the report table. Those items matter for the security model, but they are not vulnerability reports and should not be read as CVE-style findings. +For new exploitable vulnerabilities, use the private reporting path in [SECURITY.md](../../SECURITY.md). Do not include exploit details in public issues. -This page is not a vulnerability reporting channel. Report exploitable vulnerabilities privately through [SECURITY.md](../../SECURITY.md). Use public issues only for questions, documentation gaps, already-public findings, or hardening ideas that do not disclose an exploit path. - -Status reflects GitHub issue state on 2026-06-30. - -This page intentionally excludes support requests, process questions, roadmap consolidation issues, and general feature requests that only mention security-related terms in passing. +Status snapshot: 2026-06-30. General support, process, consolidation, and feature-request issues are excluded. Related hardening and roadmap trackers are listed separately. ## Report categories @@ -23,8 +19,6 @@ Use these categories when reading public security reports and already-public fin | Accepted by design | The report conflicts with the documented threat model or an intentional compatibility constraint | | Duplicate | The report repeats another public issue or private advisory response | -Rows that mention follow-up work describe the public project status, not a vulnerability disclosure path. - ## Public reports and findings These issues were filed as concrete vulnerability reports, security audit findings, or public mirrors of private advisories. Some were valid fixes. Some were accepted threat-model decisions or false positives under supported production configuration. From 09e8ed8a160e87d625eb31f642bd436c970b7e6a Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 05:33:36 +0000 Subject: [PATCH 11/13] docs: clarify security report outcomes --- docs/security/public-security-reports.md | 93 ++++++++++++------------ 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/docs/security/public-security-reports.md b/docs/security/public-security-reports.md index bb7cc2e24..004a75269 100644 --- a/docs/security/public-security-reports.md +++ b/docs/security/public-security-reports.md @@ -1,64 +1,64 @@ # Public Security Reports -This page tracks public GitHub issues filed as security reports or mirrors of private advisories. It shows whether each report is fixed, accepted by design, documentation-only, duplicate, or still open. +This page tracks public GitHub issues filed as security reports or mirrors of private advisories. It shows whether each report is fixed, documented, not a production vulnerability, duplicate, or still open. For new exploitable vulnerabilities, use the private reporting path in [SECURITY.md](../../SECURITY.md). Do not include exploit details in public issues. Status snapshot: 2026-06-30. General support, process, consolidation, and feature-request issues are excluded. Related hardening and roadmap trackers are listed separately. -## Report categories +## Report outcomes -Use these categories when reading public security reports and already-public findings: +Use these outcomes when reading public security reports and already-public findings: -| Category | Meaning | +| Outcome | Meaning | | --- | --- | -| Real blocker | Confirmed vulnerability that can compromise production security under supported configuration | -| Needs hardening | Defense-in-depth improvement that does not change the production trust model | -| Fixed | The reported behavior has been fixed or is fixed by the linked change | -| Docs-only | The behavior is intentional or lower severity, but public documentation should make it clear | -| Accepted by design | The report conflicts with the documented threat model or an intentional compatibility constraint | +| Valid report, fixed | The report was valid and was addressed by a code or configuration change | +| Valid report, documented | The report describes real behavior, but the project response is documentation or threat-model clarification rather than a code change | +| Valid hardening, open | The report is valid defense-in-depth work and remains open | +| Valid roadmap, open | The report identifies security-related design work that needs a compatibility or migration plan | +| Not a production vulnerability | The report does not compromise supported production deployments under the documented threat model | | Duplicate | The report repeats another public issue or private advisory response | ## Public reports and findings -These issues were filed as concrete vulnerability reports, security audit findings, or public mirrors of private advisories. Some were valid fixes. Some were accepted threat-model decisions or false positives under supported production configuration. +These issues were filed as concrete vulnerability reports, security audit findings, or public mirrors of private advisories. Some resulted in fixes. Some are documented design choices or not production vulnerabilities. -| Issue | Status | Category | Disposition | +| Issue | Status | Outcome | Project response | | --- | --- | --- | --- | -| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Accepted by design, optional hardening | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. Zero-padding for the unset instance ID is optional hardening | -| [#550](https://github.com/Dstack-TEE/dstack/issues/550) Compose hash computed on raw bytes, not canonicalized JSON | Closed | Accepted by design | dstack treats compose JSON as an opaque byte sequence. Any byte-level change is a different measured application configuration | -| [#551](https://github.com/Dstack-TEE/dstack/issues/551) Shell injection via `init_script` and `pre_launch_script` in compose | Closed | Accepted by design, docs-only | Scripts are application-owned code and are measured as part of app configuration. Verifiers must treat script contents as part of the application trust decision | -| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Docs-only, roadmap follow-up | Static salt is acceptable with high-entropy KMS root material and explicit context. Key versioning and rotation require a broader compatibility design | -| [#553](https://github.com/Dstack-TEE/dstack/issues/553) `derive_dh_secret` hashes PKCS#8 DER | Closed | Fixed | [#603](https://github.com/Dstack-TEE/dstack/pull/603) stabilizes the P-256 private key encoding used for derivation | -| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup | -| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Accepted by design | The setup code validates and opens the same in-memory LUKS header | -| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Open | Needs hardening | Tracks removal of transient command-line exposure for secret-bearing setup commands | -| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Open | Fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions | -| [#558](https://github.com/Dstack-TEE/dstack/issues/558) Path traversal in KMS `remove_cache` | Closed | Fixed | [#601](https://github.com/Dstack-TEE/dstack/pull/601) validates cache paths before deletion | -| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Accepted compatibility decision, docs-only | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements | -| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Accepted by design | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token | -| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Docs-only | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code | -| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Accepted threat-model decision, possible hardening | A process that can choose its own quote path is already inside the measured CVM behavior. A production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` remains possible hardening | -| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary | -| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Accepted by design | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret | -| [#565](https://github.com/Dstack-TEE/dstack/issues/565) Infinite loop in `wait_for_generation_change` | Closed | Fixed | [#596](https://github.com/Dstack-TEE/dstack/pull/596) bounds the ConfigFS generation wait loop | -| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Open | Fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size | -| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Open | Fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation | -| [#568](https://github.com/Dstack-TEE/dstack/issues/568) Webhook URL leaked via `println!` in production code | Closed | Fixed | Fixed before the issue was triaged by removing the unsafe log output in `79b8b8d2` | -| [#605](https://github.com/Dstack-TEE/dstack/issues/605) Guest agent derives identical key material for `ed25519` and `secp256k1` | Open | Accepted compatibility decision, docs-only | Existing derived key bytes are preserved. Docs state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys | -| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Open | Needs hardening | Tightening secret-bearing file writes to owner-only permissions (`0600`) is valid defense-in-depth work with no expected compatibility cost | -| [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Open | Accepted by design for dev/test deployments | `gateway_app_id` is KMS contract configuration and is publicly auditable. Production deployments must not use `"any"` | -| [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Open | Accepted by design for local/integration testing | Dev auth is measured runtime configuration, not a production mode. Production must use webhook/on-chain authorization | -| [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Open | Accepted by design for local development | The flag is measured in runtime configuration and should fail production attestation policy | -| [#610](https://github.com/Dstack-TEE/dstack/issues/610) Unauthenticated bootstrap endpoint can overwrite root keys | Closed | Accepted by design | The bootstrap endpoint does not accept caller-supplied root key material. Root keys are generated server-side, and the operator chooses which result to publish | -| [#611](https://github.com/Dstack-TEE/dstack/issues/611) Unauthenticated `/finish` endpoint can shut down KMS onboard service | Closed | Accepted by design | The onboard service is a short-lived setup flow. Premature shutdown causes operator retry, not persistent compromise or data loss | -| [#612](https://github.com/Dstack-TEE/dstack/issues/612) Gateway `register_cvm` prefers stale `app_info` over live attestation | Closed | Accepted by design | Cert-embedded `app_info` is extracted from attestation and signed by KMS. Preferring it avoids redundant extraction and is not a trust bypass | -| [#613](https://github.com/Dstack-TEE/dstack/issues/613) 10-year default certificate validity undermines attestation freshness | Closed | Accepted by design | RA-TLS certificates embed attestation evidence and verifiers validate that evidence during connection handling. Freshness policy belongs in verifier policy, not only certificate expiry | -| [#614](https://github.com/Dstack-TEE/dstack/issues/614) VMM `no_tee` flag allows launching VMs without TDX protection | Closed | Accepted by design for dev/test deployments | `no_tee` VMs cannot produce valid TDX quotes and cannot join the production trust chain unless other development-only checks are also disabled | -| [#615](https://github.com/Dstack-TEE/dstack/issues/615) Host-supplied `sys_config` not measured but influences security-critical behavior | Closed | Accepted by design | Network endpoints are not trust anchors. KMS, gateway, and PCCS trust decisions rely on cryptographic verification, not host-supplied URLs | -| [#616](https://github.com/Dstack-TEE/dstack/issues/616) Host-controlled Docker registry mirror enables image substitution attacks | Closed | Accepted by design | Registry mirrors are untrusted transport. Digest-pinned image references and measured compose configuration protect against substitution | -| [#617](https://github.com/Dstack-TEE/dstack/issues/617) Guest agent exposes raw private keys to all local processes | Closed | Accepted by design | dstack treats a CVM as one application trust domain. It does not provide per-container key isolation inside the same measured application | -| [#618](https://github.com/Dstack-TEE/dstack/issues/618) Disk encryption disableable via kernel cmdline, not measured in RTMR | Closed | Accepted by design | The kernel command line is measured into RTMR2, so changing `dstack.storage_encrypted=false` changes attestation evidence | +| [#549](https://github.com/Dstack-TEE/dstack/issues/549) Disk encryption key collision when `no_instance_id=true` and HKDF context ambiguity | Open | Valid report, documented | `no_instance_id=true` intentionally shares disk keys across instances, and the HKDF inputs have fixed lengths. No code fix has been applied. Zero-padding for the unset instance ID remains optional hardening | +| [#550](https://github.com/Dstack-TEE/dstack/issues/550) Compose hash computed on raw bytes, not canonicalized JSON | Closed | Valid report, documented | dstack treats compose JSON as an opaque byte sequence. Any byte-level change is a different measured application configuration. No code fix was applied | +| [#551](https://github.com/Dstack-TEE/dstack/issues/551) Shell injection via `init_script` and `pre_launch_script` in compose | Closed | Valid report, documented | Scripts are application-owned code and are measured as part of app configuration. Verifiers must treat script contents as part of the application trust decision. No code fix was applied | +| [#552](https://github.com/Dstack-TEE/dstack/issues/552) Static HKDF salt and no key versioning | Open | Valid roadmap, open | Static salt is acceptable with high-entropy KMS root material and explicit context. No code fix has been applied. Key versioning and rotation require a broader compatibility design | +| [#553](https://github.com/Dstack-TEE/dstack/issues/553) `derive_dh_secret` hashes PKCS#8 DER | Closed | Valid report, fixed | [#603](https://github.com/Dstack-TEE/dstack/pull/603) stabilizes the P-256 private key encoding used for derivation | +| [#554](https://github.com/Dstack-TEE/dstack/issues/554) Signature concatenation without length prefixes enables collision | Open | Valid report, fixed | [#604](https://github.com/Dstack-TEE/dstack/pull/604) enforces the 20-byte `app_id` length in CVM setup | +| [#555](https://github.com/Dstack-TEE/dstack/issues/555) LUKS header TOCTOU between validation and `luksOpen` | Open | Not a production vulnerability | The setup code validates and opens the same in-memory LUKS header. No code fix was applied | +| [#556](https://github.com/Dstack-TEE/dstack/issues/556) Disk encryption key and WireGuard key visible in `/proc/PID/cmdline` | Open | Valid hardening, open | Tracks removal of transient command-line exposure for secret-bearing setup commands | +| [#557](https://github.com/Dstack-TEE/dstack/issues/557) Runtime event log writable by any VM process | Open | Valid report, fixed | [#602](https://github.com/Dstack-TEE/dstack/pull/602) restricts runtime event-log permissions | +| [#558](https://github.com/Dstack-TEE/dstack/issues/558) Path traversal in KMS `remove_cache` | Closed | Valid report, fixed | [#601](https://github.com/Dstack-TEE/dstack/pull/601) validates cache paths before deletion | +| [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Not a production vulnerability | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. No code fix was applied | +| [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Not a production vulnerability | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. No code fix was applied | +| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Valid report, documented | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code. No code fix was applied | +| [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Not a production vulnerability | A process that can choose its own quote path is already inside the measured CVM behavior. No code fix has been applied. A production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` remains possible hardening | +| [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Valid report, fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary | +| [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Not a production vulnerability | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. No code fix was applied | +| [#565](https://github.com/Dstack-TEE/dstack/issues/565) Infinite loop in `wait_for_generation_change` | Closed | Valid report, fixed | [#596](https://github.com/Dstack-TEE/dstack/pull/596) bounds the ConfigFS generation wait loop | +| [#566](https://github.com/Dstack-TEE/dstack/issues/566) Gzip decompression bomb in RA-TLS cert extension | Open | Valid report, fixed | [#595](https://github.com/Dstack-TEE/dstack/pull/595) bounds decompressed RA-TLS event-log extension size | +| [#567](https://github.com/Dstack-TEE/dstack/issues/567) Unbounded allocation in `VecOf` decode | Open | Valid report, fixed | [#570](https://github.com/Dstack-TEE/dstack/pull/570) caps `VecOf` decode length and pre-allocation | +| [#568](https://github.com/Dstack-TEE/dstack/issues/568) Webhook URL leaked via `println!` in production code | Closed | Valid report, fixed | Fixed before the issue was triaged by removing the unsafe log output in `79b8b8d2` | +| [#605](https://github.com/Dstack-TEE/dstack/issues/605) Guest agent derives identical key material for `ed25519` and `secp256k1` | Open | Valid report, documented | Existing derived key bytes are preserved. Docs state that `path` is the domain separator and callers must use algorithm-specific paths when they require independent keys. No code fix was applied | +| [#606](https://github.com/Dstack-TEE/dstack/issues/606) App keys and decrypted env files world-readable | Open | Valid hardening, open | Tightening secret-bearing file writes to owner-only permissions (`0600`) is valid defense-in-depth work with no expected compatibility cost | +| [#607](https://github.com/Dstack-TEE/dstack/issues/607) `gateway_app_id = "any"` disables gateway identity pinning | Open | Not a production vulnerability | `gateway_app_id` is KMS contract configuration and is publicly auditable. Production deployments must not use `"any"`. No code fix was applied | +| [#608](https://github.com/Dstack-TEE/dstack/issues/608) `auth_api.type = "dev"` allows all authorization | Open | Not a production vulnerability | Dev auth is measured runtime configuration, not a production mode. Production must use webhook/on-chain authorization. No code fix was applied | +| [#609](https://github.com/Dstack-TEE/dstack/issues/609) `quote_enabled = false` bypasses attestation | Open | Not a production vulnerability | The flag is measured in runtime configuration and should fail production attestation policy. No code fix was applied | +| [#610](https://github.com/Dstack-TEE/dstack/issues/610) Unauthenticated bootstrap endpoint can overwrite root keys | Closed | Not a production vulnerability | The bootstrap endpoint does not accept caller-supplied root key material. Root keys are generated server-side, and the operator chooses which result to publish. No code fix was applied | +| [#611](https://github.com/Dstack-TEE/dstack/issues/611) Unauthenticated `/finish` endpoint can shut down KMS onboard service | Closed | Not a production vulnerability | The onboard service is a short-lived setup flow. Premature shutdown causes operator retry, not persistent compromise or data loss. No code fix was applied | +| [#612](https://github.com/Dstack-TEE/dstack/issues/612) Gateway `register_cvm` prefers stale `app_info` over live attestation | Closed | Not a production vulnerability | Cert-embedded `app_info` is extracted from attestation and signed by KMS. Preferring it avoids redundant extraction and is not a trust bypass. No code fix was applied | +| [#613](https://github.com/Dstack-TEE/dstack/issues/613) 10-year default certificate validity undermines attestation freshness | Closed | Not a production vulnerability | RA-TLS certificates embed attestation evidence and verifiers validate that evidence during connection handling. Freshness policy belongs in verifier policy, not only certificate expiry. No code fix was applied | +| [#614](https://github.com/Dstack-TEE/dstack/issues/614) VMM `no_tee` flag allows launching VMs without TDX protection | Closed | Not a production vulnerability | `no_tee` VMs cannot produce valid TDX quotes and cannot join the production trust chain unless other development-only checks are also disabled. No code fix was applied | +| [#615](https://github.com/Dstack-TEE/dstack/issues/615) Host-supplied `sys_config` not measured but influences security-critical behavior | Closed | Not a production vulnerability | Network endpoints are not trust anchors. KMS, gateway, and PCCS trust decisions rely on cryptographic verification, not host-supplied URLs. No code fix was applied | +| [#616](https://github.com/Dstack-TEE/dstack/issues/616) Host-controlled Docker registry mirror enables image substitution attacks | Closed | Not a production vulnerability | Registry mirrors are untrusted transport. Digest-pinned image references and measured compose configuration protect against substitution. No code fix was applied | +| [#617](https://github.com/Dstack-TEE/dstack/issues/617) Guest agent exposes raw private keys to all local processes | Closed | Not a production vulnerability | dstack treats a CVM as one application trust domain. It does not provide per-container key isolation inside the same measured application. No code fix was applied | +| [#618](https://github.com/Dstack-TEE/dstack/issues/618) Disk encryption disableable via kernel cmdline, not measured in RTMR | Closed | Not a production vulnerability | The kernel command line is measured into RTMR2, so changing `dstack.storage_encrypted=false` changes attestation evidence. No code fix was applied | | [#619](https://github.com/Dstack-TEE/dstack/issues/619) KMS `get_temp_ca_cert` returns temp CA private key without authentication | Closed | Duplicate | The report duplicates the private advisory response for the temp CA bootstrap flow | ## Related security roadmap and hardening @@ -70,9 +70,6 @@ These issues affect security architecture, future verification behavior, operati | [#113](https://github.com/Dstack-TEE/dstack/issues/113) Alternative to RA-TLS | Open | Architecture roadmap | Tracks possible application-level attestation or pre-registration approaches | | [#114](https://github.com/Dstack-TEE/dstack/issues/114) On-chain logs for KMS replication | Open | Auditability roadmap | Tracks transparency for KMS onboarding and replication events | | [#115](https://github.com/Dstack-TEE/dstack/issues/115) Censorship resistance in the KMS | Open | Governance roadmap | Tracks how KMS instances should prove an up-to-date chain view after de-registration or policy changes | -| [#125](https://github.com/Dstack-TEE/dstack/issues/125) Requirements for deploying dstack OS on GCP | Open | Cloud trust plumbing | Tracks cloud image packaging, app config transfer, and cloud measurement calculation | -| [#330](https://github.com/Dstack-TEE/dstack/issues/330) Self-describing hash format for Intel DCAP `reportdata` | Open | Format roadmap | Tracks a DIP for self-describing report data | | [#411](https://github.com/Dstack-TEE/dstack/issues/411) Adopt RFC 8785 JCS for canonical compose hash calculation | Open | Measurement roadmap | Tracks a possible future canonical hash scheme. Current raw-byte hashing is intentional and recorded in #550 | -| [#713](https://github.com/Dstack-TEE/dstack/issues/713) AMD SEV-SNP support tracking | Open | Platform roadmap | Tracks remaining work before AMD SEV-SNP can be called supported. SNP remains experimental and opt-in until the tracker is complete | | [#745](https://github.com/Dstack-TEE/dstack/issues/745) `secure_time: true` cannot sync because guest chrony lacks NTS | Open | Security feature bug | Tracks a secure-time boot failure. The fix is in [meta-dstack#76](https://github.com/Dstack-TEE/meta-dstack/pull/76) | | [#746](https://github.com/Dstack-TEE/dstack/issues/746) Harden AMD SEV-SNP KDS collateral fetch | Open | Availability hardening | Tracks async client, timeout, and caching hardening for SNP KDS collateral fetch. Verification remains fail-closed | From d2d14d078d9c817b679e38bf1a3a7be2663fcbb4 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 05:49:45 +0000 Subject: [PATCH 12/13] docs: revert unrelated Solana example change --- sdk/go/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/go/README.md b/sdk/go/README.md index 227ddb400..a59268af7 100644 --- a/sdk/go/README.md +++ b/sdk/go/README.md @@ -323,7 +323,7 @@ import ( "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) -keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "ed25519") +keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "secp256k1") if err != nil { log.Fatal(err) } From d604355645839be561624970aef7ae45a5cf5fb4 Mon Sep 17 00:00:00 2001 From: Hang Yin Date: Tue, 30 Jun 2026 06:42:03 +0000 Subject: [PATCH 13/13] docs: fix security SDK examples --- docs/security/public-security-reports.md | 2 +- docs/security/security-best-practices.md | 4 +- docs/security/security-model.md | 4 +- docs/tutorials/kms-build-configuration.md | 10 +++-- docs/tutorials/kms-cvm-deployment.md | 5 ++- sdk/curl/api.md | 2 +- sdk/go/README.md | 54 ++++++++++++++--------- sdk/js/README.md | 6 +-- sdk/python/README.md | 2 +- sdk/rust/README.md | 2 +- 10 files changed, 54 insertions(+), 37 deletions(-) diff --git a/docs/security/public-security-reports.md b/docs/security/public-security-reports.md index 004a75269..03c3f0470 100644 --- a/docs/security/public-security-reports.md +++ b/docs/security/public-security-reports.md @@ -37,7 +37,7 @@ These issues were filed as concrete vulnerability reports, security audit findin | [#558](https://github.com/Dstack-TEE/dstack/issues/558) Path traversal in KMS `remove_cache` | Closed | Valid report, fixed | [#601](https://github.com/Dstack-TEE/dstack/pull/601) validates cache paths before deletion | | [#559](https://github.com/Dstack-TEE/dstack/issues/559) Zero `mr_config_id` bypasses verification and weakens `mr_aggregated` identity | Open | Not a production vulnerability | Zero `mr_config_id` remains an unset-value compatibility case, and configuration changes are still reflected through RTMR-based measurements. No code fix was applied | | [#560](https://github.com/Dstack-TEE/dstack/issues/560) Admin token comparison not constant-time | Open | Not a production vulnerability | The comparison is over a SHA-256 digest of a high-entropy token, not the raw token. No code fix was applied | -| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Valid report, documented | The TLS listener allows unauthenticated bootstrap endpoints, while sensitive KMS handlers enforce client certificate and attestation checks in application code. No code fix was applied | +| [#561](https://github.com/Dstack-TEE/dstack/issues/561) KMS TLS client certificates are non-mandatory in Rocket config | Open | Valid report, documented | The TLS listener allows unauthenticated bootstrap, temp-CA bootstrap, and public endpoints. `GetTempCaCert` returns temp CA private material for bootstrap. App/KMS key release requires verified caller attestation, and certificate signing verifies the CSR signature and embedded attestation. No code fix was applied | | [#562](https://github.com/Dstack-TEE/dstack/issues/562) Configfs path overridable through an environment variable | Open | Not a production vulnerability | A process that can choose its own quote path is already inside the measured CVM behavior. No code fix has been applied. A production guard for `DCAP_TDX_QUOTE_CONFIGFS_PATH` remains possible hardening | | [#563](https://github.com/Dstack-TEE/dstack/issues/563) `simulate_quote` runtime path in production guest agent | Open | Valid report, fixed | [#582](https://github.com/Dstack-TEE/dstack/pull/582) isolates the simulator into a dedicated binary | | [#564](https://github.com/Dstack-TEE/dstack/issues/564) `GetAppEnvEncryptPubKey` unauthenticated app ID enumeration | Open | Not a production vulnerability | The RPC returns a public encryption key before an app has an attested identity, and `app_id` is not treated as secret. No code fix was applied | diff --git a/docs/security/security-best-practices.md b/docs/security/security-best-practices.md index 865c7f411..fc3fab67e 100644 --- a/docs/security/security-best-practices.md +++ b/docs/security/security-best-practices.md @@ -77,7 +77,9 @@ Development settings are intentionally easy to audit, but they are not productio - The KMS contract pins a concrete gateway app id. Do not use `gateway_app_id = "any"` for production traffic. - TEE quotes are evaluated by deployment policy, including TCB status and expected OS/application measurements. -The KMS TLS listener may keep `rpc.tls.mutual.mandatory = false` because bootstrap endpoints need to be reachable before a client has an RA-TLS certificate. Sensitive KMS routes still require the client certificate and attestation evidence in application code before releasing keys or signing certificates. +The KMS TLS listener may keep `rpc.tls.mutual.mandatory = false` because bootstrap, temp-CA bootstrap, and public metadata endpoints need to be reachable before a client has an RA-TLS certificate. `GetTempCaCert` returns temp CA private material for the bootstrap flow; treat it as bootstrap-sensitive. + +App key release and KMS key handover still require verified caller attestation from the RA-TLS client certificate. Certificate signing verifies the CSR signature and embedded attestation before signing. ## Keep private material owner-only diff --git a/docs/security/security-model.md b/docs/security/security-model.md index d819e9050..5c3bdf3fe 100644 --- a/docs/security/security-model.md +++ b/docs/security/security-model.md @@ -146,7 +146,9 @@ Production verifiers should reject deployments that use these development settin The KMS Rocket TLS listener permits connections without a client certificate because some bootstrap and public metadata endpoints must be reachable before a client has an RA-TLS certificate. That listener setting is not the authorization boundary for key material. -Sensitive KMS handlers enforce their own boundary: callers must present the expected client certificate and attestation evidence before key derivation, KMS key replication, or certificate signing succeeds. Public endpoints are limited to bootstrap, metadata, health, and metrics behavior documented for operators. +App key release and KMS key handover require verified caller attestation from the RA-TLS client certificate. Certificate signing verifies the CSR signature and the attestation embedded in the CSR before signing. + +The unauthenticated or non-client-certificate surface includes bootstrap and temp-CA bootstrap material retrieval, env-encryption public-key retrieval, metadata, health, and metrics behavior documented for operators. `GetTempCaCert` returns temp CA private material for the bootstrap flow, so operators must treat it as bootstrap-sensitive rather than harmless public metadata. ## Limitations diff --git a/docs/tutorials/kms-build-configuration.md b/docs/tutorials/kms-build-configuration.md index fef925a9c..e93e83692 100644 --- a/docs/tutorials/kms-build-configuration.md +++ b/docs/tutorials/kms-build-configuration.md @@ -187,8 +187,9 @@ certs = "/etc/kms/certs/rpc.crt" [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" # Keep the TLS listener optional because bootstrap/public endpoints must be -# reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs still -# enforce client certificate and attestation checks in their handlers. +# reachable before a client has an RA-TLS certificate. Temp-CA bootstrap material +# is bootstrap-sensitive. Key-release RPCs still require verified caller +# attestation; certificate signing verifies CSR signature and attestation. mandatory = false # Core KMS Configuration @@ -469,8 +470,9 @@ certs = "/etc/kms/certs/rpc.crt" [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" # Keep the TLS listener optional because bootstrap/public endpoints must be -# reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs still -# enforce client certificate and attestation checks in their handlers. +# reachable before a client has an RA-TLS certificate. Temp-CA bootstrap material +# is bootstrap-sensitive. Key-release RPCs still require verified caller +# attestation; certificate signing verifies CSR signature and attestation. mandatory = false # Core KMS Configuration diff --git a/docs/tutorials/kms-cvm-deployment.md b/docs/tutorials/kms-cvm-deployment.md index b3827f3aa..f86058c67 100644 --- a/docs/tutorials/kms-cvm-deployment.md +++ b/docs/tutorials/kms-cvm-deployment.md @@ -168,8 +168,9 @@ configs: [rpc.tls.mutual] ca_certs = "/etc/kms/certs/tmp-ca.crt" # Keep the TLS listener optional because bootstrap/public endpoints must be - # reachable before a client has an RA-TLS certificate. Sensitive KMS RPCs - # still enforce client certificate and attestation checks in their handlers. + # reachable before a client has an RA-TLS certificate. Temp-CA bootstrap + # material is bootstrap-sensitive. Key-release RPCs still require verified + # caller attestation; certificate signing verifies CSR signature and attestation. mandatory = false [core] diff --git a/sdk/curl/api.md b/sdk/curl/api.md index 8b864f75d..f040cbfa6 100644 --- a/sdk/curl/api.md +++ b/sdk/curl/api.md @@ -74,7 +74,7 @@ Generates a deterministic private key from the application key and returns both |-------|------|-------------|----------| | `path` | string | Path for the key. This is the domain separator for deterministic key material. | `"my/key/path"` | | `purpose` | string | Purpose for the key. Can be any string. This is used in the signature chain and does not affect the private key bytes. | `"signing"` | -| `algorithm` | string | Either `secp256k1` or `ed25519`. Defaults to `secp256k1`. For compatibility, this selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. | `ed25519` | +| `algorithm` | string | `secp256k1` (default), `k256` (alias), or `ed25519`. For compatibility, this selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. | `ed25519` | Use algorithm-specific paths, such as `wallet/ethereum` and `wallet/solana`, when independent keys are required across algorithms. diff --git a/sdk/go/README.md b/sdk/go/README.md index a59268af7..df916e7eb 100644 --- a/sdk/go/README.md +++ b/sdk/go/README.md @@ -323,7 +323,7 @@ import ( "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) -keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "secp256k1") +keyResult, err := client.GetKey(ctx, "solana/main", "wallet", "ed25519") if err != nil { log.Fatal(err) } @@ -370,41 +370,45 @@ envVars := []dstack.EnvVar{ {Key: "WALLET_MNEMONIC", Value: "abandon abandon abandon..."}, } -// 2. Obtain encryption public key from KMS API (dstack-vmm or Phala Cloud) -// (HTTP request implementation depends on your HTTP client) -publicKey := "a1b2c3d4..." // From KMS API -signature := "e1f2g3h4..." // From KMS API +// 2. Obtain encryption public key from KMS API (dstack-vmm or Phala Cloud). +// HTTP request implementation depends on your HTTP client. +kmsResponse := struct { + PublicKey string `json:"public_key"` + SignatureV1 string `json:"signature_v1"` + Timestamp uint64 `json:"timestamp"` +}{ + // Fill these fields from /prpc/GetAppEnvEncryptPubKey?json. +} // 3. Verify KMS API authenticity to prevent man-in-the-middle attacks -publicKeyBytes, _ := hex.DecodeString(publicKey) -signatureBytes, _ := hex.DecodeString(signature) +publicKeyBytes, _ := hex.DecodeString(kmsResponse.PublicKey) +signatureBytes, _ := hex.DecodeString(kmsResponse.SignatureV1) // Prefer timestamped verification to prevent replay attacks. -timestamp := uint64(1710000000) // From the KMS API response, not local time kmsIdentity, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp( publicKeyBytes, signatureBytes, "your-app-id-hex", - timestamp, + kmsResponse.Timestamp, nil, // use default freshness policy (max age 300s) ) if err != nil || kmsIdentity == nil { - log.Fatal("KMS API provided untrusted encryption key") + log.Fatal("kms API provided untrusted encryption key") } -expectedKMSIdentity := "03..." // From the DstackKms contract or deployment config -actualKMSIdentity := hex.EncodeToString(kmsIdentity) +expectedKMSIdentity := "0x03..." // From the DstackKms contract or deployment config +actualKMSIdentity := string(kmsIdentity) if actualKMSIdentity != expectedKMSIdentity { log.Fatalf("unexpected KMS identity: got %s", actualKMSIdentity) } -fmt.Println("Verified KMS public key:", actualKMSIdentity) +fmt.Println("Verified KMS identity:", actualKMSIdentity) // VerifyEnvEncryptPublicKey() is available only for explicit compatibility with // older KMS builds. It does not provide timestamp replay protection. // 4. Encrypt environment variables for secure deployment -encryptedData, err := dstack.EncryptEnvVars(envVars, publicKey) +encryptedData, err := dstack.EncryptEnvVars(envVars, kmsResponse.PublicKey) if err != nil { log.Fatal(err) } @@ -703,20 +707,26 @@ import ( "github.com/Dstack-TEE/dstack/sdk/go/dstack" ) -// Example: Verify KMS-provided encryption key -publicKey, _ := hex.DecodeString("e33a1832c6562067ff8f844a61e51ad051f1180b66ec2551fb0251735f3ee90a") -signature, _ := hex.DecodeString("8542c49081fbf4e03f62034f13fbf70630bdf256a53032e38465a27c36fd6bed7a5e7111652004aef37f7fd92fbfc1285212c4ae6a6154203a48f5e16cad2cef00") +// Example: Verify a KMS response from /prpc/GetAppEnvEncryptPubKey?json +kmsResponse := struct { + PublicKey string `json:"public_key"` + SignatureV1 string `json:"signature_v1"` + Timestamp uint64 `json:"timestamp"` +}{ + // Fill these fields from the KMS API response. +} +publicKey, _ := hex.DecodeString(kmsResponse.PublicKey) +signature, _ := hex.DecodeString(kmsResponse.SignatureV1) appID := "0000000000000000000000000000000000000000" -timestamp := uint64(1710000000) // From the KMS API response -kmsIdentity, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp(publicKey, signature, appID, timestamp, nil) +kmsIdentity, err := dstack.VerifyEnvEncryptPublicKeyWithTimestamp(publicKey, signature, appID, kmsResponse.Timestamp, nil) if err != nil || kmsIdentity == nil { - log.Fatal("KMS signature verification failed") + log.Fatal("kms signature verification failed") } -expectedKMSIdentity := "03..." // From the DstackKms contract or deployment config -actualKMSIdentity := hex.EncodeToString(kmsIdentity) +expectedKMSIdentity := "0x03..." // From the DstackKms contract or deployment config +actualKMSIdentity := string(kmsIdentity) if actualKMSIdentity != expectedKMSIdentity { log.Fatalf("unexpected KMS identity: got %s", actualKMSIdentity) } diff --git a/sdk/js/README.md b/sdk/js/README.md index 156d706d0..20cd40654 100644 --- a/sdk/js/README.md +++ b/sdk/js/README.md @@ -175,7 +175,7 @@ const wallet = createWalletClient({ account, chain: mainnet, transport: http() } ```typescript import { toKeypairSecure } from '@phala/dstack-sdk/solana' -const key = await client.getKey('wallet/solana') +const key = await client.getKey('wallet/solana', 'mainnet', 'ed25519') const keypair = toKeypairSecure(key) console.log(keypair.publicKey.toBase58()) ``` @@ -220,7 +220,7 @@ const response = await fetch(`${kmsUrl}/prpc/GetAppEnvEncryptPubKey?json`, { const publicKey = Buffer.from(response.public_key, 'hex') if (!response.signature_v1 || response.timestamp === undefined) { - throw new Error('KMS response missing timestamped signature') + throw new Error('kms response missing timestamped signature') } const signer = verifyEnvEncryptPublicKey( @@ -230,7 +230,7 @@ const signer = verifyEnvEncryptPublicKey( BigInt(response.timestamp), ) -if (!signer) throw new Error('KMS signature did not verify') +if (!signer) throw new Error('kms signature did not verify') const trustedSigners = new Set(['0x...']) // From the DstackKms contract or deployment config if (!trustedSigners.has(signer)) throw new Error(`unexpected KMS signer: ${signer}`) diff --git a/sdk/python/README.md b/sdk/python/README.md index 4093521d9..04cc88c10 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -239,7 +239,7 @@ print(account.address) ```python from dstack_sdk.solana import to_keypair_secure -key = client.get_key('wallet/solana') +key = client.get_key('wallet/solana', purpose='mainnet', algorithm='ed25519') keypair = to_keypair_secure(key) print(keypair.pubkey()) ``` diff --git a/sdk/rust/README.md b/sdk/rust/README.md index 4fe1d282f..3fe8b2ace 100644 --- a/sdk/rust/README.md +++ b/sdk/rust/README.md @@ -56,7 +56,7 @@ let testnet_key = client.get_key(Some("wallet/eth/testnet".to_string()), None).a - `path`: Key derivation path (determines the key) - `purpose` (optional): Included in signature chain message, does not affect the derived key -For compatibility, the key algorithm selects how the same derived 32-byte material is interpreted; it does not domain-separate the derivation. Use algorithm-specific paths when independent keys are required. +The Rust SDK currently requests the default `secp256k1` key material. Use distinct paths when keys must be independent. **Returns:** `GetKeyResponse` - `key`: Hex-encoded private key