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. Reports that may affect OpenDAL security should be sent to private@opendal.apache.org before public disclosure.
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:
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.
An OpenDAL deployment has these participants:
| Participant | Role in this model |
|---|---|
| Host application | Trusted caller that creates Builders, supplies config, applies Layers, 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
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.
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.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.
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.
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:
Operator B must not be signed with credentials from Operator A.disable_config_load, disable_ec2_metadata, and disable_vm_metadata must prevent the ambient credential sources they document.OpenDAL must avoid exposing credentials through debug output, error chains, log lines, tracing spans, and metrics labels.
Expected behavior:
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.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.
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.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.
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:
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.
Language bindings and FFI shims are in scope when they expose OpenDAL through a documented API.
Examples:
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.
The following are not OpenDAL vulnerabilities by default.
Storage-provider policy is owned by the backend and operator.
Examples:
The caller is responsible for choosing the storage service and endpoint.
Examples:
OpenDAL does not provide cryptographic authentication of backend bytes. Applications that need end-to-end integrity must add it above OpenDAL.
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:
../../secret from an HTTP route into Operator::read without its own authorization or sanitization.Builder::endpoint values.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.
OpenDAL does not guarantee that a trusted backend is correct.
Examples:
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.OpenDAL provides streaming APIs and optional layers, but it is not a default DoS shield.
Examples:
Operator::read or Operator::list APIs that materialize data in memory instead of streaming APIs.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.
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.
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.
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.
| 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. |
| 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. |
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.Debug implementation prints a secret access key.Operator::list call.disable_config_load = true still reads credentials from the ambient environment source it promised to disable.skip_signature = true silently downgrades HTTPS to HTTP.dav-server-opendalfs without an authn layer.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. |
We will revisit this threat model when any of the changes:
Operator through a protocol listener.MODEL-GAP.website/community/security.md currently defines the disclosure process:
private@opendal.apache.org;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”.