| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| # Apache OpenDAL Security Threat Model |
| |
| ## 1. Status |
| |
| This document defines the security boundary for Apache OpenDAL. It is intended |
| for maintainers, security reporters, downstream users, and automated security |
| scanners that need to decide whether a report describes an OpenDAL |
| vulnerability or a responsibility of the embedding application, storage backend, |
| or deployment. |
| |
| The canonical disclosure process remains |
| [`website/community/security.md`](website/community/security.md). Reports that |
| may affect OpenDAL security should be sent to `private@opendal.apache.org` |
| before public disclosure. |
| |
| ## 2. Purpose |
| |
| OpenDAL is an in-process storage access library. It gives a host application a |
| uniform `Operator` API over many storage backends. It is not a daemon, gateway, |
| identity provider, authorization service, sandbox, or multi-tenant broker. |
| |
| The purpose of this document is to help maintainers triage security reports by |
| answering three questions: |
| |
| 1. What is OpenDAL's security boundary? |
| 2. What security responsibilities do applications that use OpenDAL have? |
| 3. What security responsibilities do cloud and network storage providers have? |
| 4. Which of the following categories apply to a security report: OpenDAL vulnerabilities, |
| hardening requests, user misuse, or out-of-scope deployment issues? |
| |
| The most important premises are: |
| |
| > OpenDAL trusts storage services for fulfilling storage capabilities defined per documentation. |
| > OpenDAL also trusts users to provide secure configuration and use OpenDAL as users' storage layer. |
| |
| If a user intentionally uses OpenDAL to access an untrusted S3-compatible endpoint, |
| WebDAV server, FTP server, database, local path, or other backend, the user |
| is responsible for the consequences of configured service. OpenDAL does not |
| authenticate remote object contents, prove remote metadata correctness, or |
| protect the user from a malicious storage service that the user chose. |
| |
| That premise does not remove OpenDAL's responsibility for OpenDAL library |
| boundary. OpenDAL must still preserve OpenDAL API contracts, isolate credentials, avoid leaking secrets in debug or observability output, and avoid |
| memory-safety violations in code reachable through OpenDAL public API. |
| |
| ## 3. System Model |
| |
| An OpenDAL deployment has these participants: |
| |
| | Participant | Role in this model | |
| | --- | --- | |
| | Host application | Trusted caller that creates `Builder`s, supplies config, applies `Layer`s, and decides which end-user input may reach OpenDAL. | |
| | OpenDAL | In-process library that normalizes public API inputs, builds service requests, signs requests when configured, parses service responses, and returns data or errors. | |
| | Storage backend | A trusted service that the host application use. e.g., An OpenDAL uses connects to S3, or a database uses OpenDAL communicates with Google Cloud. OpenDAL trusts a trusted service for backend-side authentication, object bytes, metadata, consistency, and durability. | |
| | End user of the host application | Out of OpenDAL's direct model. The host application must authenticate, authorize, and sanitize end-user requests before calling OpenDAL. | |
| | Network attacker | Out of scope unless the report shows OpenDAL weakened the configured transport. TLS and proxy policy are delegated to the HTTP client and host environment. | |
| |
| OpenDAL doesn't use principal model. A `Operator` takes control of a backend service by user-provided credentials, root and other configurations. Every operation via an |
| `Operator` instance shares the same OpenDAL-level authority. |
| A typical interaction will be: |
| |
| ``` |
| Trusted service <-> Backend <-> Operator <-> Host Application <-> End user |
| | | |
| |------------------------| |
| OpenDAL code surface |
| ``` |
| |
| ## 4. Security Boundary |
| |
| OpenDAL's security boundary is the public library boundary plus the internal |
| state that OpenDAL owns behind that boundary. |
| |
| The following properties are in scope for OpenDAL security. |
| |
| ### 4.1 Public API contract |
| |
| OpenDAL must handle inputs accepted by the public API without memory-safety |
| violations, data races, panics across FFI boundaries, or inconsistent internal |
| state. |
| |
| Examples: |
| |
| - `Operator` path normalization must be deterministic and consistent with the |
| documented path rules in `core/core/src/raw/path.rs`. |
| - `Operator::from_uri(...)` and `Operator::via_iter(...)` must build the service |
| and root implied by trusted caller config. |
| - Public operation options such as ranges, conditional headers, metadata, and |
| presign expiry must be encoded according to the selected service contract. |
| |
| OpenDAL does not decide whether a host application's end user is allowed to use |
| a path. The host application owns that policy. However, once the host |
| application passes a path into OpenDAL, OpenDAL must not accidentally map it to |
| OpenDAL does not care whether a host application's end user has permissions for a path access. A host application decides what and how to interact with data and path with a configured service via an `Operator` instance. In another word, if |
| a host application passes a path into OpenDAL, OpenDAL must not map it to |
| a different backend location than that backend's API contract describes. e.g. when passing `/path` to an `Fs` operator, OpenDAL should only access `/path`. |
| |
| ### 4.2 Local resource boundary |
| |
| Remote storage services are trusted by configuration. Local resources touched |
| directly by OpenDAL are different because OpenDAL itself constructs host |
| filesystem paths, cache directories, temporary files, and local database paths. |
| |
| For local services and layers, OpenDAL is responsible for the filesystem effects |
| created by its own path construction. |
| |
| Examples: |
| |
| - `services::Fs` documents `root` as the root under which operations happen. |
| Reports showing that normalized OpenDAL paths can escape that configured root |
| through OpenDAL's path construction are in scope. |
| - `services::Foyer` and `FoyerLayer` can use on-disk cache storage. Reports about |
| OpenDAL writing cache data outside the configured cache location, leaking |
| credentials into cache metadata, or corrupting unrelated local files are in |
| scope. |
| - `atomic_write_dir` and temporary-write behavior are in scope when OpenDAL |
| creates or renames files itself. |
| |
| Symlink behavior for local filesystems should be documented explicitly by the |
| service. A report about symlink traversal should not be closed solely because |
| OpenDAL is a library; it should be triaged against the service's documented |
| local filesystem contract. |
| |
| ### 4.3 Credential isolation |
| |
| OpenDAL must not leak credentials between independent operators, services, or layers within the same process. |
| |
| Sharing OpenDAL operators across processes (e.g., via fork) while reusing configurations and credentials remains users' responsibility. |
| |
| Examples: |
| |
| - A request from `Operator` B must not be signed with credentials from |
| `Operator` A. |
| - An OAuth token, temporary credential, signer context, or credential-provider |
| cache must not be shared across operators unless the sharing is explicitly |
| configured by the caller. |
| - `disable_config_load`, `disable_ec2_metadata`, and `disable_vm_metadata` must |
| prevent the ambient credential sources they document. |
| |
| ### 4.4 Credential redaction and observability |
| |
| OpenDAL must avoid exposing credentials through debug output, error chains, log |
| lines, tracing spans, and metrics labels. |
| |
| Expected behavior: |
| |
| - Builder `Debug` implementations redact credential fields. |
| - `LoggingLayer` may emit paths because paths are operation context, but it must |
| not emit access keys, secret keys, bearer tokens, session tokens, private key |
| material, or signer state. |
| - Metrics labels include service-level dimensions such as scheme, namespace, |
| root, operation, error, status code, and service operation. They should not |
| include credentials. |
| - Tracing and other observability layers follow the same credential-redaction |
| rule. |
| |
| Paths, namespace names, and roots can be sensitive in some deployments. OpenDAL |
| does not treat them as credentials by default; callers that need stronger |
| privacy must choose their observability layers and sinks accordingly. |
| |
| ### 4.5 Request construction and signing |
| |
| OpenDAL is responsible for constructing requests that match the configured |
| service, endpoint, root, path, and operation. |
| |
| Examples: |
| |
| - `skip_signature = true` must only skip request signing. It must not silently |
| change HTTPS to HTTP, disable endpoint validation, or weaken unrelated |
| transport behavior. |
| - `allow_anonymous` is a deprecated compatibility alias only for the services |
| that still expose it. |
| - A service must not send credentials to an endpoint other than the endpoint |
| selected by the trusted caller config. |
| |
| If the caller configures a malicious endpoint, sending requests to that endpoint |
| is caller responsibility. If OpenDAL ignores the caller's configured endpoint or |
| mixes it with another operator's credentials, that is in scope. |
| |
| ### 4.6 Response handling robustness |
| |
| OpenDAL trusts the configured backend for semantic correctness: object bytes, |
| ETags, metadata, listing order, backend authentication and authorization decisions, and durability claims |
| belong to the backend. |
| |
| OpenDAL is still responsible for handling backend responses without violating |
| its own library invariants. |
| |
| Examples: |
| |
| - XML and JSON parsers used by services must not cause memory-safety violations |
| or uncontrolled panics reachable through the public API. |
| - Error parsing must not leak credentials. |
| - HTTP response body accounting must follow the implemented contract. For |
| non-`HEAD` responses without `Content-Encoding`, OpenDAL records |
| `Content-Length` and checks the consumed body length. |
| |
| A malicious or compromised trusted backend returning false data is not by |
| itself an OpenDAL vulnerability. A parser bug in OpenDAL that turns a malformed |
| response into memory unsafety, credential disclosure, or process compromise may |
| be an OpenDAL vulnerability. |
| |
| ### 4.7 FFI and language bindings |
| |
| Language bindings and FFI shims are in scope when they expose OpenDAL through a |
| documented API. |
| |
| Examples: |
| |
| - C ABI functions must uphold ownership and lifetime rules documented for that |
| ABI. |
| - Binding-level crashes or use-after-free bugs reachable from safe binding APIs |
| are in scope. |
| - Bare `unsafe` blocks are not findings by themselves; the finding must show a |
| reachable violation of the documented API contract. |
| |
| Each binding has its own version. A security property confirmed for Rust core |
| version `X` is not automatically confirmed for every binding release named `X`. |
| |
| ## 5. Out Of Scope |
| |
| The following are not OpenDAL vulnerabilities by default. |
| |
| ### 5.1 Backend-side authorization and configuration |
| |
| Storage-provider policy is owned by the backend and operator. |
| |
| Examples: |
| |
| - Public S3 bucket policy. |
| - HDFS permissions. |
| - POSIX file mode bits outside OpenDAL's own path construction. |
| - OAuth scopes granted to Google Drive, Dropbox, OneDrive, or similar services. |
| - Database user privileges. |
| |
| ### 5.2 Malicious storage services selected by the caller |
| |
| The caller is responsible for choosing the storage service and endpoint. |
| |
| Examples: |
| |
| - A caller configures an attacker-controlled S3-compatible endpoint and the |
| endpoint receives signed requests. |
| - A WebDAV, FTP, SFTP, HTTP, database, or SaaS endpoint lies about object |
| contents, metadata, ETags, timestamps, or consistency. |
| - A backend returns data that fails an application-level integrity check. |
| |
| OpenDAL does not provide cryptographic authentication of backend bytes. |
| Applications that need end-to-end integrity must add it above OpenDAL. |
| |
| ### 5.3 Host application authentication and authorization |
| |
| OpenDAL does not authenticate end users, authorize per-user access, or decide |
| whether end-user input is allowed to become an OpenDAL path, endpoint, metadata |
| value, or body. |
| |
| Examples: |
| |
| - A web service forwards `../../secret` from an HTTP route into `Operator::read` |
| without its own authorization or sanitization. |
| - A host application lets a tenant choose arbitrary `Builder::endpoint` values. |
| - A host application gives multiple tenants the same `Operator` over the same |
| backend root. |
| |
| These may be serious vulnerabilities in the host application, but they are not |
| OpenDAL vulnerabilities unless OpenDAL violates one of the boundaries in |
| section 4. |
| |
| ### 5.4 Backend correctness and data integrity |
| |
| OpenDAL does not guarantee that a trusted backend is correct. |
| |
| Examples: |
| |
| - ETag is provider-defined and is not a MAC. |
| - Listing order and consistency are backend properties. |
| - `Content-Type`, `Content-Length`, timestamps, and user metadata are backend |
| responses. OpenDAL may parse or check them for protocol handling, but does not |
| turn them into cryptographic truth. |
| |
| ### 5.5 Resource exhaustion by default |
| |
| OpenDAL provides streaming APIs and optional layers, but it is not a default |
| DoS shield. |
| |
| Examples: |
| |
| - A backend returns a very large object. |
| - A backend returns many listing pages. |
| - A caller uses `Operator::read` or `Operator::list` APIs that materialize data |
| in memory instead of streaming APIs. |
| - The caller does not apply `TimeoutLayer`, `ConcurrentLimitLayer`, or |
| `ThrottleLayer`. |
| |
| Resource-exhaustion reports are OpenDAL vulnerabilities only when they show that |
| OpenDAL violates a documented bound or consumes resources independently of the |
| operation requested by the trusted caller and backend. |
| |
| ### 5.6 Transport policy selected outside OpenDAL |
| |
| TLS certificate validation, CA bundles, proxies, and custom HTTP clients are |
| properties of the HTTP client and host environment. A report is in scope only |
| if an OpenDAL option silently weakens transport contrary to its documented |
| meaning. |
| |
| ### 5.7 Deployment shape of integrations |
| |
| Integrations such as `dav-server` and `unftp-sbe` can expose an `Operator` over |
| a network listener. Authentication and authorization for that listener belong |
| to the host process and deployment. |
| |
| Code-level bugs in the integration are in scope for that integration. A |
| deployment that exposes it without the intended authn/authz layer is not an |
| OpenDAL core vulnerability. |
| |
| ### 5.8 Supply chain, release, and project infrastructure |
| |
| Dependency freshness, GitHub Actions hardening, release signing, branch |
| protection, and ASF infrastructure policy are important, but they are outside |
| this OpenDAL library threat boundary unless a separate project policy says |
| otherwise. |
| |
| ## 6. Component Scope |
| |
| | Component family | Examples | Boundary notes | |
| | --- | --- | --- | |
| | Core API | `Operator`, `blocking::Operator`, `raw::Access`, operation options | Public API contract, path normalization, request construction, response handling, and memory safety are in scope. | |
| | Remote object stores | S3, GCS, Azure Blob, OSS, COS, OBS, B2, TOS, Swift, AzDLS, AzFile, LakeFS, Upyun, Vercel Blob | Backend contents and authz are trusted. OpenDAL credential handling, request signing, endpoint use, and parser robustness are in scope. | |
| | Remote protocols | HTTP, WebDAV, FTP, SFTP, WebHDFS, HDFS-family services | Remote service is trusted. Protocol implementation, credential handling, and parser robustness are in scope. | |
| | SaaS services | Google Drive, Dropbox, OneDrive, GitHub, Hugging Face, Aliyun Drive, pCloud, Koofr, Seafile, Yandex Disk | OAuth scope and remote correctness are backend/operator concerns. Token handling and redaction are in scope. | |
| | Database and KV services | MySQL, PostgreSQL, SQLite, Redis, MongoDB, SurrealDB, D1, Cloudflare KV, GridFS, etcd, Memcached, TiKV, FoundationDB, RocksDB, Redb, Persy, Sled, Cacache, GHAC, Vercel Artifacts | Backend authz and data correctness are trusted. Local file effects from embedded databases are in scope when OpenDAL config constructs paths. | |
| | Local filesystem services | `fs`, `compfs`, `monoiofs`, `opfs` | OpenDAL path construction and documented root behavior are in scope. Host-level permissions and caller authz are out of scope. | |
| | Cache services and layers | `foyer`, `FoyerLayer`, immutable-index layer | Cache directories, credential redaction, and local file effects are in scope when configured through OpenDAL. Cache hit correctness follows the layer contract. | |
| | Observability layers | logging, tracing, metrics, OpenTelemetry, Prometheus, dtrace, fastmetrics | Credential leakage is in scope. Paths and roots may be emitted as operational context unless the layer documents stronger privacy. | |
| | Control layers | retry, timeout, throttle, concurrent-limit, route, capability-check, chaos | Layer behavior must match its documented contract and must not cross-contaminate credentials or operator state. | |
| | Language bindings | C, C++, D, Dart, .NET, Go, Haskell, Java, Lua, Node.js, OCaml, PHP, Python, Ruby, Swift, Zig | Binding API safety, FFI ownership, and contract parity are in scope for the binding. | |
| | Examples, benches, fixtures, edge tests | `examples/`, `core/benches/`, `fixtures/`, `core/edge/` | Not production API. Bugs here are usually not OpenDAL vulnerabilities unless copied into shipped library behavior. | |
| |
| ## 7. Triage Dispositions |
| |
| | Disposition | Use when | |
| | --- | --- | |
| | `VALID` | The report shows a violation of an in-scope boundary in section 4, reachable through documented OpenDAL APIs or shipped bindings. | |
| | `VALID-HARDENING` | There is no clear security-boundary violation, but OpenDAL's API makes dangerous misuse common enough that maintainers choose to harden behavior or documentation. | |
| | `OUT-OF-SCOPE: trusted-backend` | The report requires the configured storage backend to be malicious, compromised, or semantically wrong, and OpenDAL does not violate its own parser, credential, or memory-safety boundary. | |
| | `OUT-OF-SCOPE: caller-authz` | The report depends on the host application forwarding unauthorized end-user input into OpenDAL. | |
| | `OUT-OF-SCOPE: caller-config` | The report depends on a trusted caller choosing a malicious endpoint, credential, root, layer, or HTTP client. | |
| | `OUT-OF-SCOPE: deployment` | The report depends on exposing an integration or application without the deployment's intended authn/authz controls. | |
| | `OUT-OF-SCOPE: infrastructure` | The report is about release, CI, dependency, or ASF infrastructure policy rather than the OpenDAL library boundary. | |
| | `BY-DESIGN: property-not-provided` | The report asks OpenDAL to provide a property explicitly not provided here, such as backend-byte authentication or default resource caps. | |
| | `MODEL-GAP` | The report cannot be classified by this document. Treat this as evidence that the model needs revision. | |
| |
| ## 8. Examples |
| |
| ### 8.1 In scope |
| |
| - `services::Fs` maps a normalized OpenDAL path outside the configured `root` |
| through OpenDAL path construction. |
| - `Operator` B signs a request with credentials configured for `Operator` A. |
| - A builder `Debug` implementation prints a secret access key. |
| - A service-specific XML parser can trigger memory unsafety through a normal |
| `Operator::list` call. |
| - A binding safe API can trigger use-after-free in the C ABI. |
| - `disable_config_load = true` still reads credentials from the ambient |
| environment source it promised to disable. |
| - `skip_signature = true` silently downgrades HTTPS to HTTP. |
| |
| ### 8.2 Out of scope by default |
| |
| - The caller configures an attacker-controlled S3-compatible endpoint and that |
| endpoint receives signed requests. |
| - A storage service returns false object bytes or a misleading ETag. |
| - A host application forwards an untrusted tenant path to OpenDAL without its |
| own authorization checks. |
| - A bucket policy allows public reads. |
| - A caller exposes `dav-server-opendalfs` without an authn layer. |
| - A caller reads a huge object with an API that materializes the whole object in |
| memory. |
| |
| ### 8.3 Security and documentation improvement |
| |
| - A common misuse is easy enough that many users repeat it. |
| - A service's local filesystem behavior is surprising but not clearly contrary |
| to the documented contract. |
| - A layer emits non-credential operational context that can be sensitive in some |
| deployments. |
| |
| ## 9. Maintainer Decisions |
| |
| The following decisions are part of this model. |
| |
| | Topic | Decision | |
| | --- | --- | |
| | Remote backends | OpenDAL trusts the remote backend selected by caller configuration. Malicious or incorrect remote backend behavior is out of scope unless OpenDAL violates its own parser, credential, memory-safety, or API boundary while handling the response. | |
| | `services::Fs` lexical root | OpenDAL must not map normalized operation paths outside the configured `root` through its own lexical path construction. | |
| | `services::Fs` symlinks | `services::Fs` follows normal host filesystem semantics. It is not a sandbox against symlinks that already exist under the configured `root`, unless a service-specific document later promises stronger confinement. | |
| | Canonical location | This file, `SECURITY-THREAT-MODEL.md`, is the repository-level threat model. The project security page may link to it, but the disclosure process remains there. | |
| | Version binding | A report should be triaged against the threat model version present in the affected release tag or maintenance branch. | |
| | Component drift | When services, layers, bindings, or local resource surfaces change, this file should be updated in the same pull request or a linked follow-up. | |
| | Observability privacy | Credentials are secrets and must be redacted. Paths, roots, and namespaces are operational context, not credentials by default, but deployments that treat them as sensitive should configure observability accordingly. | |
| |
| ## 10. Revision Triggers |
| |
| We will revisit this threat model when any of the changes: |
| |
| - A service or layer starts storing credentials outside process memory. |
| - A service or layer adds a new local filesystem write surface. |
| - A credential-loading option changes default behavior. |
| - A request-signing option changes semantics. |
| - A new binding or FFI surface is added. |
| - A new integration exposes an `Operator` through a protocol listener. |
| - A vulnerability report is classified as `MODEL-GAP`. |
| - The project decides to treat a previously caller-owned property as an |
| OpenDAL-provided property. |
| |
| ## 11. Relationship To Existing Security Documentation |
| |
| `website/community/security.md` currently defines the disclosure process: |
| |
| - report concerns to `private@opendal.apache.org`; |
| - include the project name and reproduction details; |
| - report privately before public disclosure. |
| |
| This threat model is additive. It does not replace the disclosure process. The |
| security page should link here as the canonical reference for "what counts as an |
| OpenDAL vulnerability". |