pjfanning commented on code in PR #3478:
URL: https://github.com/apache/pekko/pull/3478#discussion_r3876337029


##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,420 @@
+# Apache Pekko — Threat Model
+
+**Status:** Reviewed by the Apache Pekko PMC, 2026-08-27. The thirteen 
questions this document was drafted around are answered in §14 and carry 
*(maintainer)* provenance; the residual module in/out split noted in §2 and Q6 
is the one open item.
+
+| | |
+| --- | --- |
+| **Project** | Apache Pekko (core toolkit) |
+| **Written against** | commit `90b02d60`, `main` |
+| **Date** | 2026-08-27 |
+| **Authors** | ASF Security team, at the request of the Pekko PMC |
+| **Version binding** | This model is versioned alongside the project. A 
report against Pekko version *N* is triaged against the model as it stood at 
*N*, not at `main`. |
+| **Reporting** | Findings that violate a §8 property should be reported per 
[`SECURITY.md`](SECURITY.md). Findings that fall under §3 or §9 will be closed 
citing this document. |
+
+**Provenance legend.** Every non-trivial claim is tagged:
+*(documented)* — stated in Pekko's own docs, cited.
+*(maintainer)* — stated by a Pekko maintainer in review of this document.
+*(inferred)* — reasoned from code or config defaults, **not yet confirmed**; 
each has a matching question in §14.
+
+**Provenance mix:** 43 documented / 48 maintainer / 3 inferred. The documented 
share is unusually high because Pekko's own remoting and serialization docs 
already state much of the trust model explicitly. The §5a default rulings — 
previously the largest inferred block — are now answered by the §5b posture 
statement and §14 Q1 to Q5. What remains inferred is the residual module in/out 
split (§14 Q6).
+
+## §1 Overview
+
+Apache Pekko is a Scala/Java toolkit for building concurrent, distributed and 
resilient message-driven applications. Its unit of computation is the actor: an 
object with private state that communicates only by asynchronous message 
passing. Pekko extends that model across machines — an `ActorSystem` can 
address actors on remote nodes as if they were local, and a cluster of such 
systems provides membership, sharding, singletons and replicated data. That 
transparency is the source of most of this document: **the network is not 
incidental to Pekko, it is part of the programming model**, and the security 
consequences follow from where the toolkit assumes that network sits.
+
+---
+
+## §2 Scope and intended use
+
+Pekko is an **in-process library** that the application embeds and configures. 
It is not a server, not a daemon, and ships no runnable artifact that an 
operator deploys on its own. There is consequently no "Pekko instance" to 
secure independently of the application hosting it.
+
+Three caller roles matter, and they are not equally trusted:
+
+- **The embedding application** — fully trusted. It constructs the 
`ActorSystem`, supplies configuration, and already shares the JVM with Pekko.
+- **The operator/deployer** — trusted for the instance. Chooses transport, TLS 
material, and the network the node sits on. Most of §10 lands here.
+- **The remote peer** — another `ActorSystem` that has associated over 
remoting. Its trust level is the central question of this model, and §7 answers 
it.
+
+### Component families
+
+| Family | Modules | Entry point | Leaves the process? | In model |
+| --- | --- | --- | --- | --- |
+| Actor core | `actor`, `actor-typed`, `slf4j`, `coordination` | 
`ActorSystem`, `ActorRef` | no | **yes** |
+| Classic IO | `actor` (`org.apache.pekko.io`) | `IO(Tcp)`, `IO(Udp)`, 
`IO(Dns)` | **network — if the application binds** | **yes** |
+| Remoting | `remote` | Artery transport (`tcp` / `tls-tcp` / `aeron-udp`); 
classic remoting (netty), deprecated but supported *(maintainer — §14 Q13)* | 
**network** | **yes — primary surface** |
+| Cluster | `cluster`, `cluster-typed`, `cluster-tools`, `cluster-sharding*`, 
`cluster-metrics` | gossip, membership, sharding | **network** (via remoting) | 
**yes** |
+| Replicated data | `distributed-data` | CRDT replication | **network** (via 
remoting) | **yes** |
+| Serialization | `serialization-jackson`, `serialization-jackson3` | 
`Serializer` SPI | deserializes network bytes | **yes — critical** |
+| Wire encoding | `protobuf-v3` | shaded protobuf runtime | parses remoting 
and cluster wire bytes | **yes** |
+| Streams | `stream`, `stream-typed` | `Source`/`Flow`/`Sink`; `Tcp`, `TLS`, 
`FileIO`, `Framing` | **network / filesystem — if the application uses those 
connectors** | **yes** |
+| Persistence | `persistence`, `persistence-typed`, `persistence-query`, 
`persistence-shared` | journal / snapshot plugin SPI | **storage backend** | 
**yes**, boundary at the SPI |
+| PKI | `pki` | PEM/keystore parsing | **reads files** | **yes** |
+| Discovery | `discovery` | service-discovery SPI | **network / DNS** | 
**yes** |
+| OSGi | `osgi` | bundle activator | classloading | **yes** *(maintainer — §14 
Q6)* |
+| Test kits | `*-testkit`, `multi-node-testkit`, `*-tests`, `persistence-tck`, 
`stream-tests-tck` | — | — | **no** — §3 |
+| Benchmarks | `bench-jmh` | — | — | **no** — §3 |
+| Build / docs | `docs`, `project`, `scripts`, `legal`, `kubernetes` 
(test-cluster provisioning scripts), `plugins`, `bill-of-materials`, 
`scala-nightly` | — | — | **no** — §3 |
+
+*(inferred — the in/out split is the ASF Security team's proposal, except 
`osgi`, which is confirmed in model; see §14 Q6)*
+
+---
+
+## §3 Out of scope (explicit non-goals)
+
+- **Test kits, benchmarks, build tooling and documentation sources.** These 
ship in the repository but are not part of the security-supported surface. A 
finding in `bench-jmh` or any `*-tests` module is `OUT-OF-MODEL: 
unsupported-component`. *(inferred — §14 Q6)*
+- **Pekko is not a sandbox.** Actors are not an isolation boundary. Any code 
running in the JVM can reach any actor's state by ordinary means; the actor 
model is a concurrency discipline, not a security control. *(maintainer — §14 
Q4)*
+- **Pekko is not an authorization framework.** It carries no notion of a 
principal, role, or permission on a message. Application-level authorization is 
the embedding application's job. *(maintainer — §14 Q11)*
+- **A Pekko cluster is not a multi-tenancy boundary.** The documentation is 
explicit that *"you'll have to trust all cluster nodes the same in a Pekko 
cluster anyway"* *(documented — `remote-security.md`)*. Separating 
mutually-distrusting tenants across nodes of one cluster is not a supported 
deployment.
+- **Attackers who already control the embedding process** are out of scope — 
they have already won. *(maintainer — §14 Q11)*
+- **This document describes the `apache/pekko` core toolkit.** Its technical 
content — the §2 component families, the §5a defaults, the §8 properties — is 
about that codebase. Other Apache Pekko deliverables (Pekko Management, Pekko 
HTTP, Pekko gRPC, Pekko Connectors, Pekko Projection, the persistence plugins) 
ship from their own repositories, and this model does not enumerate their 
surfaces.
+
+    That is a limit on **coverage, not on standing**. Reporting and triage are 
identical across all Pekko repositories: the same address (see 
[`SECURITY.md`](SECURITY.md)), the same PMC, and the same posture — an 
implementation defect is Pekko's to fix, while a request to change a default is 
a change request under §5b, not a vulnerability. A finding in another Pekko 
repository is **not** `OUT-OF-MODEL: unsupported-component`; that disposition 
is for the §3 components above, not for code that simply lives elsewhere. 
*(maintainer — §14 Q6)*
+
+---
+
+## §4 Trust boundaries and data flow
+
+**The primary trust boundary is the remoting network boundary**, and Pekko's 
documentation places it unusually explicitly:
+
+> "An `ActorSystem` should not be exposed via Pekko Cluster or Pekko Remote 
over plain Aeron/UDP or TCP to an untrusted network, such as the Internet. It 
should be protected by network security, such as a firewall. If that is not 
considered enough protection, TLS with mutual authentication should be enabled."
+> — *(documented — `remote-security.md`)*
+
+and states the consequence of crossing it:
+
+> "As soon as an actor system can connect to another remotely, it may in 
principle send any possible message to any actor contained within that remote 
system."
+> — *(documented — `remote-security.md`, Untrusted Mode)*
+
+Read together, these define the model: **remoting assumes it runs on a network 
the operator has already restricted.** Association is the security decision; 
once a peer is associated, it is inside. Pekko offers two mechanisms to tighten 
that (TLS mutual authentication, untrusted mode) but neither converts remoting 
into a boundary that is safe to face the open internet *(documented — see §9)*.
+
+The application's own boundaries — the HTTP endpoint, the message broker, the 
database — sit **outside** Pekko and are the embedding application's 
responsibility.
+
+### Reachability preconditions per family
+
+A finding must meet its family's precondition to be in-model:
+
+- **Remoting** — reachable from bytes arriving on the Artery transport, *and* 
the report must state whether it assumes the network-isolation assumption above 
is intact. A finding that requires an attacker already on the cluster network 
is judged under §7, not automatically valid.
+- **Serialization** — reachable from a message payload deserialized by a 
**configured, enabled** serializer. Findings reachable only when 
`allow-java-serialization = on` are judged under §5a.
+- **Cluster / distributed-data** — reachable from gossip or replication 
traffic originating at an **associated peer**. Per §7 such a peer is trusted, 
so these are typically out of model unless the finding shows a pre-association 
reach.
+- **Actor core / streams** — reachable from data the embedding application 
passes in. Trusted by default; a finding must show the data crosses an 
application boundary that Pekko itself defines.
+- **Persistence** — reachable from journal or snapshot contents. The store is 
trusted *(maintainer — §14 Q5)*, so a finding requiring write access to it is 
out of model; a defect in Pekko's replay handling is not.
+- **PKI** — reachable from PEM/keystore material. Operator-supplied and 
trusted per §6.
+
+---
+
+## §5 Assumptions about the environment
+
+- **Runtime.** A conformant JVM. Pekko does not defend against a hostile JVM, 
a hostile classpath, or an attacker with local code execution in the same 
process. *(maintainer — §14 Q11)*
+- **Network adjacency.** *"Best practice is that Pekko remoting nodes should 
only be accessible from the adjacent network."* *(documented — 
`remote-security.md`)*
+- **PKI scope.** Where TLS is used, every certificate issued by the same 
internal PKI tree is equivalent: *"there is still a risk that an attacker can 
gain access to a valid certificate by compromising any node with certificates 
issued by the same internal PKI tree."* *(documented — `remote-security.md`)*
+- **Clock.** Failure detection and gossip do **not** depend on other nodes' 
clocks: the failure detector reads only the local clock, and gossip ordering 
uses logical `VectorClock` counters. The exception is `LWWRegister`/`LWWMap`, 
which merge by wall-clock timestamp and therefore assume reasonably 
synchronised clocks across writers *(documented — `typed/distributed-data.md`, 
and the `LWWRegister` scaladoc)*. Pekko does not defend against adversarial 
clock manipulation on a cluster node *(maintainer — §14 Q12; see Q9)*.
+- **Entropy.** On Linux with SHA1PRNG, the docs recommend 
`-Djava.security.egd=file:/dev/urandom` to avoid blocking, noting it *"is NOT 
as secure because it reuses the seed."* *(documented — `remote-security.md`)*
+
+### What Pekko does not do to its host
+
+These are negative claims, rarely written down anywhere. Each is confirmed and 
carries the citation, or the exception, behind it *(maintainer — §14 Q7)*:
+
+- Installs no signal handlers and spawns no child processes — no 
`sun.misc.Signal`/`SignalHandler`, `Runtime.exec` or `ProcessBuilder` in the 
main sources. It does register **one JVM shutdown hook**, via 
`CoordinatedShutdown` (`actor/.../actor/CoordinatedShutdown.scala:381`).
+- Opens no listening socket of its own accord. Remoting binds when configured; 
`org.apache.pekko.io.Tcp`/`Udp` (in `pekko-actor`) and `stream.scaladsl.Tcp` 
(in `pekko-stream`) bind only on an explicit application call. Pekko never 
binds a port the application did not ask for.
+- **Reads environment variables during configuration startup, but never 
modifies them** *(maintainer — §14 Q7)*. Pekko itself calls neither 
`System.getenv` nor `sys.env` anywhere in the main sources; environment values 
reach it only through HOCON `${?VAR}` substitution when `ConfigFactory.load` 
resolves the configuration (`actor/.../actor/ActorSystem.scala:281`). That path 
is deliberate and documented — it is how the docs tell operators to supply 
passwords (§10.8).
+- Writes to logging via the configured logger. One exception: 
`StandardOutLogger` prints to stdout with `println` 
(`actor/.../event/Logging.scala:1024` onward). It carries the very early 
startup log, before the configured loggers are running, and is bounded by 
`pekko.stdout-loglevel`, which defaults to `WARNING`.
+- Does not mutate process-global state at initialization — no 
`System.setProperty`, `Locale.setDefault` or `TimeZone.setDefault` in the main 
sources.
+
+---
+
+## §5a Configuration variants that change the security envelope
+
+Pekko's security posture is set almost entirely by configuration. **Every row 
below whose default is the weaker value needs a maintainer ruling** — see §14.
+
+| Setting | Default | Effect | Maintainer stance |
+| --- | --- | --- | --- |
+| `pekko.actor.allow-java-serialization` | `off` | On, exposes the JVM 
deserialization attack surface to any message payload. Docs: *"highly 
discouraged to enable in production"* *(documented — `serialization.md`)* | 
Secure default. Enabling it transfers gadget-chain defence to the operator — 
§5b, §14 Q2 *(maintainer)* |
+| `pekko.remote.artery.transport` | `tcp` | **Plaintext.** No peer 
authentication and no confidentiality on the wire. `tls-tcp` opts into TLS | 
Compatibility default — §5b, §14 Q1 *(maintainer)* |
+| `pekko.remote.artery.ssl.config-ssl-engine.require-mutual-authentication` | 
`on` | Both ends present certificates *(documented)* | Secure default |
+| `…ssl.config-ssl-engine.hostname-verification` | `off` | Off, a valid cert 
from the trusted PKI authenticates regardless of which host presents it. Docs 
*recommend* `on` but ship `off` *(documented)* | Compatibility default, warned 
at runtime — §5b, §14 Q3 *(maintainer)* |
+| `pekko.remote.artery.untrusted-mode` | `off` | On, blocks inbound system 
messages, `PossiblyHarmful` messages, remote deployment, remote DeathWatch, and 
actor selections outside `trusted-selection-paths` *(documented)* | Hardening; 
adoption is the operator's call — §5b, §14 Q4 *(maintainer)* |
+| `pekko.remote.artery.trusted-selection-paths` | `[]` | Allow-list of actor 
paths that may receive selections under untrusted mode *(documented)* | Follows 
Q4 |
+| `pekko.remote.deployment.enable-allow-list` | `off` | On, restricts which 
actor classes a peer may remote-deploy *(documented — `remoting.md`)* | 
Hardening; adoption is the operator's call — §5b, §14 Q4 *(maintainer)* |
+| `pekko.remote.classic.untrusted-mode` | `off` | Classic-remoting equivalent 
of the artery flag *(reference.conf:381)* | Follows Q4 *(maintainer — §14 Q13)* 
|
+| `pekko.remote.classic.trusted-selection-paths` | `[]` | As above 
*(reference.conf:387)* | Follows Q4 |
+| `pekko.remote.classic.netty.tcp.enable-ssl` | `false` | Classic's default 
transport is plaintext netty TCP *(reference.conf:582)* | Follows Q1 
*(maintainer — §14 Q13)* |
+| `pekko.actor.serialize-messages` / `serialize-creators` | `off` | Testing 
aids that force serialization round-trips. Not security controls. Docs: *"this 
is only intended for testing"* *(documented — 
`actor/src/main/resources/reference.conf`)* | Not a security knob |
+
+---
+
+## §5b Security posture: hardening, not secure-by-default
+
+Pekko is a long-lived toolkit whose deployment base is inherited from Akka. 
Its configuration defaults are chosen for compatibility with those deployments, 
in which operators have already been tasked with securing the network Pekko 
runs on and controlling who may reach and message a deployed system. Changing a 
default to a more restrictive value breaks those deployments on upgrade, 
sometimes without a clear signal as to why.
+
+Pekko therefore takes the following position *(maintainer)*:
+
+1. **Defaults are compatibility choices, not security claims.** §5a lists 
every setting whose default affects the security envelope; §10 lists what the 
operator must do as a result. Read together they are the contract: Pekko states 
what it does not provide, and states what it expects of the operator instead.
+2. **A report that a default should be more restrictive is not a vulnerability 
report.** It is a change request, and is closed as `BY-DESIGN: 
default-configuration` (§13).
+3. **Proposals to change a default are welcome, and belong on the development 
list.** The PMC will weigh them in good faith on their merits — the 
compatibility cost, whether a migration path exists, and whether a major 
version is in flight. Defaults can and do change; they change through project 
discussion, not as the remediation of a security report.
+4. **If an implementation is wrong, Pekko fixes it.** Where a control does not 
do what it is documented to do once enabled, that is a defect, in scope, at the 
severity §8 assigns. This posture governs which value ships as the default — 
never whether the mechanism works.
+
+---
+
+## §6 Assumptions about inputs
+
+For a toolkit whose surface is a wire protocol, the useful table is keyed by 
**message class**, not by function.
+
+| Source | Input | Attacker-controllable? | Who must enforce what |
+| --- | --- | --- | --- |
+| Artery transport | Inbound frame headers / framing | **Yes if the 
network-isolation assumption fails** | Operator: network isolation (§10), or 
TLS |
+| Artery transport | Serialized user-message payload | **Yes**, from an 
associated peer | Pekko: only enabled serializers run. App: validate semantic 
content |
+| Artery transport | System messages (`Create`, `Terminate`, `Watch`, 
`Supervise`) | **Yes**, from an associated peer unless untrusted mode is on | 
Operator: `untrusted-mode` if peers are less than fully trusted |
+| Artery transport | `PossiblyHarmful` messages (`PoisonPill`, `Kill`) | 
**Yes**, same condition | Same |
+| Artery transport | Remote-deployment `Props` | **Yes**, same condition | 
Operator: `enable-allow-list` |
+| Cluster | Gossip / membership state | From an **associated** peer — trusted 
per §7 | — |
+| `distributed-data` | Replicated CRDT deltas | From an associated peer — 
trusted per §7 | — |
+| Persistence | Journal / snapshot contents on replay | **No** — the store is 
trusted *(maintainer — §14 Q5)* | Operator/DBA: secure the store |
+| `pki` | PEM / keystore files | **No** — operator-supplied, trusted | 
Operator: protect key material |
+| `discovery` | Service-discovery responses (DNS, K8s API) | **Potentially** — 
depends on the resolver | Operator: trust the discovery mechanism |
+| `io.Tcp` / `io.Udp` | Bytes on an application-bound socket | **Potentially** 
— depends where the application exposes it | App: it chose to bind, defines the 
protocol, and owns what it exposes |
+| `stream.Tcp` / `stream.TLS` | Bytes on an application-bound stream server | 
**Potentially** — as above | App: as above. TLS itself is delegated to the 
JDK's JSSE |
+| `Framing` / `JsonFraming` | Delimited or length-prefixed frames | 
**Potentially** where fed from a network source | App: supplies 
`maximumFrameLength`, which bounds frame size |
+| `stream.FileIO` | File contents at an application-supplied path | Depends on 
the path | App |
+| Config | `application.conf`, system properties | **No** — trusted, part of 
the deployment | Operator |
+
+**Size and rate.** Artery imposes frame-size limits and the failure detector 
bounds how long an unresponsive peer is tolerated. These are tuning parameters, 
not security controls *(maintainer — §14 Q8)*.
+
+---
+
+## §7 Adversary model
+
+**In scope:**
+
+- **An unassociated network attacker** who can reach the remoting port — in a 
deployment where the operator's isolation assumption has held, this attacker 
should not exist; where it does, the relevant question is whether they can 
achieve anything **before** association completes. Pre-association reachability 
is the sharpest in-model attack surface. *(maintainer — §14 Q1)*
+- **An attacker supplying message content** to an otherwise legitimate peer — 
e.g. data that originates at the application's own untrusted edge and is 
forwarded into an actor message. *(maintainer — §14 Q11)*
+
+**Explicitly out of scope:**
+
+- **An associated peer behaving arbitrarily.** There is no Byzantine-peer 
model. The documentation is direct: *"you'll have to trust all cluster nodes 
the same in a Pekko cluster anyway"* *(documented)*, and *"as soon as an actor 
system can connect to another remotely, it may in principle send any possible 
message to any actor contained within that remote system"* *(documented)*. **A 
finding whose precondition is "a cluster member misbehaves" is out of model** — 
there is no honest-majority threshold to state, because the model has no notion 
of a dishonest member. This generalises to every cluster protocol — cluster 
membership, sharding, singleton and `distributed-data` alike: **Pekko makes no 
guarantee of being able to recognise a compromised node.** Failure detection is 
heartbeat-based (`remote/.../PhiAccrualFailureDetector.scala`), so it 
identifies members that stop responding, not members that respond dishonestly; 
a compromised node that keeps heartbeating is indistinguishabl
 e from a healthy one. *(maintainer — §14 Q9)*
+- **An attacker holding any certificate from the cluster's PKI tree.** 
Documented as equivalent to cluster access *(documented)*.
+- **An attacker with code execution in the embedding JVM.** Already inside the 
trust boundary.
+- **Side-channel observers.** Pekko makes no timing or memory-access 
guarantees. *(maintainer — §14 Q11)*
+
+---
+
+## §8 Security properties Pekko provides
+
+| # | Property & conditions | Violation symptom | Severity | Provenance |
+| --- | --- | --- | --- | --- |
+| P1 | **Java serialization is disabled by default**; Pekko uses it for none 
of its own internal messages | A payload deserialized via Java serialization 
under default config | **Critical** — RCE class | *(documented — 
`serialization.md`)* |
+| P2 | The disabled Java serializer **logs rejected attempts** under the 
`SECURITY` marker, and those *"SHOULD be treated as potential attacks which the 
serializer prevented"* | Silent acceptance where rejection + log is expected | 
High | *(documented — `serialization.md`)* |
+| P3 | **Remote deployment is not remote code loading.** The actor class must 
already be present on the target system | A peer causing a class absent from 
the target's classpath to execute | **Critical** | *(documented — 
`remoting.md`)* |
+| P4 | With `enable-allow-list = on`, only listed actor classes may be 
remote-deployed onto this node | An unlisted class deployed | High | 
*(documented — `remoting.md`)* |
+| P5 | With `untrusted-mode = on`, inbound system messages, `PossiblyHarmful` 
messages, remote deployment, remote DeathWatch and non-allow-listed actor 
selections are **dropped and logged** | Any of these taking effect despite the 
flag | High | *(documented — `remote-security.md`)* |
+| P6 | With `transport = tls-tcp`, TLS is applied and **mutual authentication 
is on by default** — the server side also requests and verifies the client's 
certificate | Association completing without peer certificate verification | 
**Critical** | *(documented — `remote-security.md`)* |
+| P7 | Certificate rotation is supported for mTLS in Kubernetes without 
cluster restart | Rotation causing association failure or silent downgrade | 
Medium | *(documented — `remote-security.md`; **2.0+ only**, absent from the 
released 1.x docs — 
[snapshot](https://pekko.apache.org/docs/pekko/snapshot/remote-security.html#mtls-with-rotated-certificates-in-kubernetes))*
 |
+
+**Note the shape of this list:** P4, P5 and P6 are all *conditional on a 
non-default setting*. Under stock configuration, the properties Pekko actively 
provides at the network boundary are P1, P2 and P3 — the rest of the posture is 
delegated to the operator via §10. This is a deliberate design, but it is the 
single most important thing for a triager to understand.
+
+---
+
+## §9 Security properties Pekko does **not** provide
+
+- **No peer authentication by default.** With the default `transport = tcp` 
there is no shared secret, no certificate, and no handshake credential. Any 
host that can reach the port and speak Artery can attempt association. 
*(maintainer — §14 Q1; §5b)*
+- **No confidentiality or integrity on the wire by default.** Same cause. 
*(maintainer — §14 Q1; §5b)*
+- **No intra-cluster authorization.** Once associated, a peer may address any 
actor in the system. There is no per-actor, per-message, or per-peer permission 
model. *(documented)*
+- **No Byzantine fault tolerance, and no compromised-node detection.** See §7. 
Cluster protocols assume members are honest; there is no threshold below which 
arbitrary member behaviour is tolerated *(documented — `remote-security.md`)*, 
and Pekko offers no mechanism that would identify a member as compromised in 
the first place *(maintainer — §14 Q9)*.
+- **No bound on blast radius from one compromised node.** Documented 
explicitly for the PKI case *(documented)*.
+- **No protection once Java serialization is enabled.** Turning it on 
re-exposes the full JVM deserialization surface; the docs place this squarely 
on the operator. *(documented)*
+
+### False friends
+
+These are the assumptions integrators most often bring with them, and each is 
wrong:
+
+- **Untrusted mode is not a security boundary.** *"Untrusted mode does not 
give full protection against attacks by itself. It makes it slightly harder to 
perform malicious or unintended actions"* *(documented — 
`remote-security.md`)*. It is hardening. Treating it as a substitute for 
network isolation is a §11 misuse.
+- **`PossiblyHarmful` is a marker, not an authorization mechanism.** It is a 
compile-time trait that untrusted mode consults. It confers no protection when 
untrusted mode is off.
+- **A service mesh is not a substitute for remoting security.** *"Encryption 
and authentication via a service mesh is not a replacement for Pekko Cluster 
remoting security"* — Pekko's peer-to-peer addressing has requirements a mesh 
does not satisfy *(documented — `remote-security.md`; **2.0+ only**, absent 
from the released 1.x docs — 
[snapshot](https://pekko.apache.org/docs/pekko/snapshot/general/remoting.html#service-mesh))*.
+- **TLS mutual authentication does not give per-node identity guarantees by 
default**, because `hostname-verification` ships `off` — any cert from the 
trusted PKI authenticates as any node. *(documented + config default)*
+- **The actor boundary is not a security boundary.** Message-passing isolation 
is a concurrency property, not a confidentiality one.
+
+### Well-known attack classes left to the caller
+
+- **JVM deserialization gadget chains** — mitigated by P1 only so long as Java 
serialization stays off, and only for payloads Pekko itself deserializes; 
application-level serializers are the application's problem. Pekko integrates 
**no** serialization filter: `JavaSerializer.fromBinary` performs an unfiltered 
`ObjectInputStream.readObject` (`actor/.../serialization/Serializer.scala`). An 
operator who enables Java serialization must supply the allow list themselves 
through the JVM — `-Djdk.serialFilter` or a process-wide `ObjectInputFilter` — 
and owns that entirely *(maintainer — §14 Q2)*.
+- **Resource-exhaustion via message volume or size** — CPU cost is not in 
itself a security concern, and volume from an associated peer is out of model. 
Only disproportionate cost, where work explodes relative to a single input, is 
a defect. See §14 Q8.
+- **DNS / service-discovery spoofing** — `discovery` trusts the resolver it is 
configured with.
+- **Storage-layer tampering** on persistence journals and snapshot stores — 
the store is trusted, and securing it belongs to whoever administers it 
*(maintainer — §14 Q5)*.
+
+---
+
+## §10 Downstream responsibilities
+
+The operator or embedding application must:
+
+1. **Keep remoting off untrusted networks.** Firewall the remoting port to the 
adjacent network. This is the assumption the whole model rests on 
*(documented)*.
+2. **Enable `tls-tcp` if the network is not sufficiently trusted**, and set 
`hostname-verification = on` unless hostnames are genuinely dynamic 
*(documented)*.
+3. **Leave `allow-java-serialization = off`.** If it must be enabled for 
legacy compatibility, treat the deployment as having no deserialization 
protection *(documented)*, and **maintain your own gadget-chain allow list** 
via `-Djdk.serialFilter` or a process-wide `ObjectInputFilter`. Pekko supplies 
no filter of its own, and findings that require the flag to be on are out of 
model *(maintainer — §14 Q2)*.
+4. **Treat `SECURITY`-marked log entries as security signals**, not noise. The 
disabled Java serializer marks rejected attempts this way *(documented)*; the 
TLS providers use the same marker to report a disabled hostname verification 
and the use of default keystore passwords *(`ConfigSSLEngineProvider`)*.
+5. **Scope the PKI tree to the cluster.** Any certificate it issues is cluster 
access *(documented)*.
+6. **Consider `untrusted-mode = on` and `enable-allow-list = on`** where peers 
are less than fully trusted — understanding both are hardening, not boundaries.
+7. **Never place mutually-distrusting tenants in one cluster** *(documented)*.
+8. **Supply passwords by environment substitution, not literals in config 
files** *(documented)*, and **replace the shipped defaults**. Both SSL blocks 
ship `key-store-password`, `key-password` and `trust-store-password` as 
`"changeme"` (`reference.conf:701`, `:1205`); Pekko warns under the `SECURITY` 
marker if they survive into a running system.
+9. **Secure the persistence store.** Pekko trusts journal and snapshot 
contents on replay and does not validate them as potentially hostile, so access 
control and integrity for the database or store are the administrator's 
responsibility *(maintainer — §14 Q5)*.
+10. **Protect the key material itself.** §10.5 scopes what a certificate 
grants; this is the file-level counterpart. Keystores, truststores and PEM 
material are operator-supplied and trusted by §6 — Pekko validates neither 
their provenance nor their permissions.
+11. **Keep message-content logging off in production.** 
`log-received-messages` and `log-sent-messages` (`reference.conf:862`, `:866`, 
and `:393`, `:397` for classic) and `pekko.actor.debug.receive` 
(`actor/.../reference.conf:787`) all write message contents to the log, and 
`pekko.log-config-on-start` (`:50`) writes the resolved configuration — which, 
per §10.8, is where secrets pulled in by environment substitution end up. All 
four default to `off`; turning any on moves payloads or credentials into the 
logging system, whose protection is the operator's.
+12. **Understand that transport encryption exists only on `tls-tcp`.** Neither 
`tcp` nor `aeron-udp` offers an encryption option *(documented — 
`remote-security.md`)*, so on those transports network isolation is not one 
control among several, it is the only one.
+13. **Trust, or secure, the discovery mechanism.** `discovery` accepts 
whatever its configured resolver returns (§6); Pekko does not authenticate DNS 
or service-registry responses.
+
+---
+
+## §11 Known misuse patterns
+
+- **Exposing remoting or cluster ports to the internet**, on the theory that 
TLS or untrusted mode makes it safe. Both are explicitly documented as 
insufficient alone.
+- **Enabling `allow-java-serialization` for prototyping convenience and 
shipping it.** The docs anticipate exactly this path.
+- **Relying on a service mesh** for cluster authentication *(documented as 
insufficient)*.
+- **Using cluster membership as a tenancy or privilege boundary.**
+- **Enabling TLS but leaving `hostname-verification = off`** and assuming 
per-node identity.
+- **Treating actor encapsulation as a confidentiality guarantee** within a 
single JVM.
+
+---
+
+## §11a Known non-findings (recurring false positives)
+
+Feed this section to scanners and AI triage as a suppression list.
+
+- **"Remote deployment permits arbitrary class instantiation."** Remote 
deployment is *not* remote code loading — the class must already be on the 
target's classpath *(P3, documented)*. Absent a way to introduce a class, this 
is not RCE.
+- **"Remoting transport defaults to plaintext."** Correct, and by design under 
the §4 network-isolation assumption. In-model only if the finding shows harm 
reachable **pre-association**; a request to change the default is `BY-DESIGN: 
default-configuration` per §5b.
+- **"`PoisonPill` can be sent remotely to shut down a system."** Documented 
behaviour, gated by `untrusted-mode` *(documented — `remote-security.md`)*.
+- **"`hostname-verification` is disabled by default."** Known and documented, 
with the trade-off spelled out for dynamic-hostname deployments, and warned at 
runtime under `LogMarker.Security`. A request to change the default is 
`BY-DESIGN: default-configuration` per §5b.
+- **Findings in `*-tests`, `*-testkit`, `bench-jmh`, `docs`** — `OUT-OF-MODEL: 
unsupported-component` per §3.
+- **"SHA1PRNG with `/dev/urandom` reuses the seed."** Documented trade-off, 
deliberately recommended to avoid blocking *(documented)*.

Review Comment:
   This new doc was generated using AI in the main and it just found stuff in 
our own Pekko docs.
   https://github.com/search?q=repo%3Aapache%2Fpekko+SHA1PRNG&type=code
   
   No problem reviewing this but this threat model entry basically means we 
won't accept someone telling us to change the docs or default configs as a CVE 
issue. This line is in the 'Known non-findings' section.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to