Skip to content

Add a draft threat model and wire it for discoverability - #3478

Open
potiuk wants to merge 21 commits into
apache:mainfrom
potiuk:asf-security/threat-model-2026-08-27
Open

Add a draft threat model and wire it for discoverability#3478
potiuk wants to merge 21 commits into
apache:mainfrom
potiuk:asf-security/threat-model-2026-08-27

Conversation

@potiuk

@potiuk potiuk commented Aug 27, 2026

Copy link
Copy Markdown
Member

Motivation

The Pekko PMC asked the ASF Security team for a draft threat model to refine, as
preparation for a Claude security scan. Pekko already documents its security posture
well — remote-security.md, serialization.md and remoting.md between them state
most of the trust model — but that material is spread across three files and states it
implicitly, rather than in a form a triager (or a scanning agent) can cite when
classifying a finding.

Separately, the AGENTS.mdSECURITY.md chain that a scanning agent follows to
locate a project's model does not resolve today: there is no SECURITY.md in the repo.

Modification

  • THREAT_MODEL.md — a v0 draft. Every claim is tagged (documented) with a
    citation into Pekko's own docs, or (inferred) with a matching open question in §14.
    40 documented / 0 maintainer / 14 inferred.
  • SECURITY.md — reporting policy (security@apache.org; Pekko does not operate a
    separate project security list), a link to the threat model, and the two assumptions
    that catch most reporters.
  • AGENTS.md — a ## Security section pointing at both.

Nothing the existing docs assert has been dropped or weakened. §15 is a back-map
from each existing statement to the section that now carries it, so you can diff the two.

Result

The chain AGENTS.mdSECURITY.mdTHREAT_MODEL.md resolves on main, and
triagers get a citable document with a closed set of dispositions (§13).

§14 holds 13 questions, each stated as a proposed answer — confirming or correcting
is enough, no prose needed. The two that most change the document:

  • Q1pekko.remote.artery.transport ships tcp, so a stock cluster has no peer
    authentication. Is that the supported production posture given the documented
    network-isolation assumption
    , so a report of "unauthenticated peer can associate" is
    out of model when it assumes internet exposure — but valid if it shows harm reachable
    pre-association from an adjacent-network host?
  • Q4 — are untrusted-mode and the remote deployment allow list security
    boundaries
    , or hardening? The draft says hardening, on the strength of the
    documented "untrusted mode does not give full protection against attacks by itself".

One conclusion is worth flagging explicitly because it disposes of a whole class of
scan findings: the draft reads §7 as having no Byzantine-peer model, on the strength
of "you'll have to trust all cluster nodes the same in a Pekko cluster anyway" 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."
If that
generalises from remoting to sharding, singleton and distributed-data (Q9), then any
finding whose precondition is "a cluster member misbehaves" is out of model.

This is a draft and should not be treated as canonical until at least Q1 and Q4 are
answered.
Happy to fold the answers in and push, or hand it over entirely — the PMC
owns the document.

Tests

Not run - docs only

References

None - requested by the Pekko PMC chair on the ASF security scan thread

### Motivation
The Pekko PMC asked the ASF Security team for a draft threat model to refine,
as preparation for a Claude security scan. Pekko documents its security posture
well in remote-security.md, serialization.md and remoting.md, but that material
is spread across the docs and states the trust model implicitly rather than in a
form a triager (or a scanning agent) can cite when classifying a finding.

Separately, the AGENTS.md -> SECURITY.md chain a scanning agent follows to locate
a project's model does not currently resolve: there is no SECURITY.md in the repo.

### Modification
- THREAT_MODEL.md: a v0 draft following the Scovetta rubric. Every claim is tagged
  (documented) with a citation, or (inferred) with a matching open question in §14.
  40 documented / 0 maintainer / 14 inferred.
- SECURITY.md: reporting policy pointing at security@apache.org, plus a link to
  the threat model and the two assumptions that catch most reporters.
- AGENTS.md: a Security section pointing at both.

Nothing the existing docs assert has been dropped or weakened; §15 is a back-map
from each existing statement to the section that now carries it.

### Result
The discovery chain AGENTS.md -> SECURITY.md -> THREAT_MODEL.md resolves on main,
and triagers have a citable document with a closed set of dispositions (§13).

§14 holds 13 questions for the PMC, each stated as a proposed answer to confirm or
correct. The highest-value ones are Q1 (is the plaintext `transport = tcp` default
the supported production posture, given the documented network-isolation
assumption?) and Q4 (are untrusted-mode and the deployment allow list security
boundaries, or hardening?). The document is not ready to be treated as canonical
until those are answered.

### Tests
Not run - docs only

### References
None - requested by the Pekko PMC chair on the ASF security scan thread
@potiuk
potiuk force-pushed the asf-security/threat-model-2026-08-27 branch from 283901d to 4de7f97 Compare August 27, 2026 12:09
### Motivation

Review of the v0 draft found the component-scope tables understate Pekko's
network surface, and two cited claims are documented only on the 2.0 line.

### Modification

- §2/§4/§5/§6 - `pekko-actor` ships `org.apache.pekko.io.Tcp`/`Udp`/`Dns` and
  `pekko-stream` ships `Tcp`, `TLS`, `FileIO`, `Framing`, so the "actor core is
  purely in-process" claim and the "streams leave the process only via
  connectors the app supplies" row were both wrong. Added the matching input
  rows so a framing defect routes to a §13 disposition.
- §2 - added `protobuf-v3`; listed `plugins`, `bill-of-materials` and
  `scala-nightly` as out of scope.
- §5a - added the classic-remoting knobs, which are deprecated but shipped and
  CI-gated, and were previously absent.
- §5a/§15 - `serialize-messages` is documented as test-only in reference.conf,
  so Q13 is answered; reused the slot for classic remoting's scope.
- §8 P7 and §9 - flagged the cert-rotation and service-mesh citations as 2.0+
  and linked the snapshot docs, since neither is in the released 1.x docs.
- §1 - added the heading §15 already back-mapped to.
- SECURITY.md - `remote-security.html` 404s on `current`; pointed at
  `remoting-artery.html#remote-security`, which resolves on both lines.
- security/index.md - named `security@apache.org` to match SECURITY.md, and
  linked both new documents so the docs site closes the same chain.

### Result

Scope tables match the code, every citation resolves for the version it claims,
and §14 still holds 13 questions.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

The previous commit corrected §2/§5 to record that `pekko-actor` ships
`org.apache.pekko.io.Tcp`/`Udp` and `pekko-stream` ships `Tcp`, `TLS`, `FileIO`
and `Framing`. It also added a §4 sentence declaring parsing and framing
defects reachable from an application-bound socket to be in model. That second
part is a scope ruling, not a factual correction, and it was neither tagged
`(inferred)` nor raised as a §14 question, so it entered the document without
maintainer sign-off.

It was also too broad: it asserted such bytes are attacker-controlled when the
application may bind localhost, it did not distinguish Pekko's transport
plumbing from the application's own protocol, and it swept in `stream.TLS`,
which delegates to the JDK's JSSE.

### Modification

- §4 - removed the exception sentence.
- §6 - the application-bound socket rows now describe the inputs without
  asserting an obligation on Pekko; attacker-controllability is stated as
  conditional on where the application exposes the socket.

### Result

§2, §5 and §6 describe the surface accurately, and §4 makes no scope claim
about it either way. Whether defects in Pekko's own transport and framing code
are in model is left open for the maintainers.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

An earlier review commit rewrote the upstream-coordination paragraph on the
assumption that the draft had dropped a statement from the docs. It had not:
`docs/src/main/paradox/security/index.md` on `main` already carries the same
generic wording, so the draft was faithful to it and the rewrite was
unnecessary. Restoring the sentence alongside the rewrite left the same claim
stated twice in consecutive paragraphs.

### Modification

Removed the added paragraph, leaving the original sentence in place.
`SECURITY.md` now differs from the draft only in the Remote Security link,
which pointed at a page that does not exist on the released docs.

### Result

No duplicated statement, and the file matches the wording already published on
the documentation site.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

The draft left the §5a defaults marked UNRESOLVED and carried no maintainer
provenance at all. Pekko's position is that it is a hardening toolkit rather
than a secure-by-default one: its deployment base is inherited from Akka, and
operators there have already been tasked with securing the network Pekko runs
on and controlling who may reach a deployed system. Tightening a default breaks
those deployments on upgrade.

That position needs stating, because the rest of the model depends on it and
because a threat model claiming Pekko is secure by default would not survive
contact with `reference.conf`.

### Modification

- **§5b** - new section stating the posture: defaults are compatibility
  choices, not security claims; a request to tighten one is a change request
  rather than a vulnerability report; such proposals are welcome on the
  development list and weighed in good faith; and a control that does not do
  what it documents once enabled is a defect Pekko fixes.
- **§13** - new `BY-DESIGN: default-configuration` disposition, which closes a
  report while pointing at the route to propose the change.
- **§14** - Q1, Q3 and Q4 answered and retained in place so cross-references
  still resolve. Two proposed dispositions are corrected as they did not fit
  §13's own definitions: Q1 routed an unassociated attacker to
  `adversary-not-in-scope`, which §13 reserves for an associated peer, a PKI
  certificate or in-JVM execution, and which §7 contradicts by listing that
  attacker as in scope; Q4 routed a bypass of an enabled control to
  `VALID-HARDENING`, which §13 defines as violating no §8 property, though such
  a bypass violates P5 or P4.
- **§5a, §7, §9, §11a** - stance cells filled in and the claims that were
  inferred pending these questions retagged `(maintainer)`.

### Result

Provenance moves from 42/0/14 to 41/12/9, the §5a table has no unresolved
cells, and §14 holds ten open questions rather than thirteen.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q2 asked how a deserialization finding that requires
`allow-java-serialization = on` should be triaged. The draft proposed
`OUT-OF-MODEL: non-default-build` but left unstated what an operator who
enables the flag is then responsible for, which matters because Pekko provides
nothing to help them: `JavaSerializer.fromBinary` performs an unfiltered
`ObjectInputStream.readObject` and there is no `ObjectInputFilter` integration
anywhere in the project.

### Modification

- **§14 Q2** - answered. Findings requiring the flag are out of model,
  gadget chains included. Two carve-outs are stated explicitly, per §5b.4: a
  serious defect in Pekko's own serialization implementation remains in scope
  and may warrant a CVE, and Java deserialization occurring despite the flag
  being `off` violates §8 P1 and is valid at Critical.
- **§9** - records that Pekko integrates no serialization filter, cites the
  call site, and names the JVM-level levers an operator has instead.
- **§10.3** - the operator responsibility now says to maintain a gadget-chain
  allow list via `-Djdk.serialFilter` or a process-wide `ObjectInputFilter`.
- **§5a** - stance cell updated.

### Result

§14 holds nine open questions. Provenance moves to 41 documented / 16
maintainer / 9 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q5 asked whether replay should treat journal and snapshot bytes as untrusted.
It should not. Securing the database or persistence store belongs to whoever
administers it, and Pekko does not take responsibility for treating persisted
values as potentially compromised.

### Modification

- **§14 Q5** - answered. A finding whose precondition is write access to the
  journal or snapshot store is `OUT-OF-MODEL: trusted-input`. The answer is
  scoped to the store: a defect in Pekko's own replay handling stays in scope
  per §5b.4.
- **§4, §6, §9** - the storage-trust question is replaced by the ruling.
- **§13** - journal and snapshot contents named in the `trusted-input`
  disposition.
- **§10** - new item 9, since §5b makes this list the operator contract and it
  carried nothing about the persistence store.

Also corrected a cross-reference: §4's PKI bullet cited §14 Q5, which is the
persistence question. PKI material is stated as trusted in §6.

### Result

§14 holds eight open questions. Provenance moves to 41 documented / 21
maintainer / 9 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q6 asked two things about the §2 module split: whether `kubernetes/` is
supported code, and whether `osgi` should stay in model given its classloading
surface. The `osgi` half is settled: it is a barely used feature and the project
may eventually remove it rather than carry the maintenance overhead, but while
it ships, security reports against it are accepted.

### Modification

- **§14 Q6** - marked partly answered. `osgi` stays in model and a finding
  there is not `OUT-OF-MODEL: unsupported-component`. The `kubernetes/`
  question and the rest of the split remain open.
- **§2** - the `osgi` row and the table footnote record the ruling.
- **§12** - the list of conditions that would change the model covered only
  promotion of a module into the supported surface. Removal is now named too,
  since `osgi` is a candidate and dropping it would change how findings there
  are triaged.

### Result

§14 holds seven fully open questions and one partly answered. Provenance moves
to 41 documented / 23 maintainer / 10 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q6's remaining half asked whether `kubernetes/` is supported code. It is not a
module at all: four files that provision a GKE test cluster, with no build
definition. The Kubernetes functionality people would report against -
discovery, bootstrap, lease - is not in this repository; it ships from Apache
Pekko Management.

That exposed a larger gap. Nothing in the document said which repository it
covers. Outside the header's "core toolkit", a triager had no way to tell where
a Pekko Management or Pekko HTTP finding belongs, and §13 offered no routing
for one.

### Modification

- **§14 Q6** - answered. `kubernetes/` stays out of scope as build tooling, and
  the Kubernetes implementation is recorded as living in a separate deliverable.
- **§3** - new non-goal stating that this document covers `apache/pekko` only.
  Add-on deliverables are named, with the routing made explicit: out of model
  *for this document* is not a dismissal, reports go to the same address, and
  they are triaged on the same terms - an implementation defect is Pekko's to
  fix, a request to change a default is a §5b change request.
- **§2** - the build row says what `kubernetes/` actually contains.

### Result

§14 holds seven open questions. Provenance moves to 41 documented / 26
maintainer / 10 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

The previous commit sent a finding in another Apache Pekko repository to
`OUT-OF-MODEL: unsupported-component`. That is wrong. §13 defines that
disposition as landing in a §3 component - test kits, benchmarks, build
tooling - and applying it to code that simply ships from a different
repository reads as a dismissal of a report that is in fact accepted
normally.

Pekko Management issues are reported the same way core issues are. The
repository differs; the process does not.

### Modification

Reworded the §3 entry so it limits coverage rather than standing: this
document enumerates the core toolkit's surfaces and does not enumerate the
other deliverables', but reporting, triage, the address and the §5b posture are
identical across all of them. States explicitly that such a finding is not
`OUT-OF-MODEL: unsupported-component`, so the disposition is not misapplied.
§14 Q6 follows the same correction.

### Result

No disposition implies a report is out of scope purely because of which Pekko
repository it lands in.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q7's §5 negative claims were written as bare assertions with nothing a reviewer
could check, and one of the five had already proved wrong. Q8 asked for a
categorical line on resource growth driven by a remote peer.

### Modification

**Q8 - answered.** Super-linear in message size is a bug and is valid;
constant-factor is not. Two caveats recorded: artery already bounds message size
by configuration, so the rule's input is bounded on the remoting path; and the
rule speaks to size, leaving exhaustion driven by message volume from an
associated peer subject to §7.

**Q7 - partly answered.** Environment variables are read during configuration
startup and never modified. Pekko calls neither `System.getenv` nor `sys.env`
anywhere in the main sources; values arrive only through HOCON substitution when
`ConfigFactory.load` resolves the configuration, which is the documented way to
supply passwords.

The remaining §5 claims now carry citations, and two were narrower than written:
`CoordinatedShutdown` registers a JVM shutdown hook, and `StandardOutLogger`
prints to stdout during early startup, bounded by `pekko.stdout-loglevel`.
Verified absent from the main sources: `sun.misc.Signal`, `SignalHandler`,
`Runtime.exec`, `ProcessBuilder`, `System.setProperty`, `Locale.setDefault`,
`TimeZone.setDefault`.

### Result

§14 holds five open questions. Provenance moves to 41 documented / 29
maintainer / 10 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q9 asked whether §7's no-Byzantine-peer conclusion, reached from the remoting
documentation, generalises to cluster membership, sharding, singleton and
`distributed-data`. It does, and for a stronger reason than the draft gave:
Pekko has no guarantee of being able to recognise a compromised node at all.

### Modification

- **§14 Q9** - answered. No subsystem claims resilience against a misbehaving
  member. A finding whose precondition is "a cluster member misbehaves" is
  `OUT-OF-MODEL: adversary-not-in-scope`, and so is one that assumes Pekko
  should have detected the compromise.
- **§7** - the generalisation is now stated rather than inferred, with the
  reason: failure detection is heartbeat-based
  (`PhiAccrualFailureDetector.scala`), so it identifies members that stop
  responding, not members that respond dishonestly. A compromised node that
  keeps heartbeating is indistinguishable from a healthy one.
- **§9** - the property is widened from "no Byzantine fault tolerance" to
  include the absence of any compromised-node detection, which is the part a
  reporter is more likely to assume exists.

### Result

§14 holds four open questions. Provenance moves to 41 documented / 32
maintainer / 9 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q7's remaining claims now each carry a code citation, so confirming them is a
read rather than an investigation. Q10 and Q11 were policy questions with no
code dependency.

### Modification

- **Q7 - answered.** No signal handlers, child processes or process-global
  mutation, verified absent from the main sources. Two claims stand narrower
  than first written and say so in §5: `CoordinatedShutdown` registers one JVM
  shutdown hook, and `StandardOutLogger` prints to stdout during early startup
  bounded by `pekko.stdout-loglevel`.
- **Q10 - answered.** Records which of the three security documents is
  canonical for what, and that the other two link to this one for scope rather
  than restating it. Carries a maintenance note: the reporting wording is
  duplicated between `SECURITY.md` and `security/index.md` and has already
  drifted once, so until one becomes a pointer to the other, both must be
  changed together.
- **Q11 - answered.** The non-goals are confirmed. Two clarifications added to
  the draft's wording: the side-channel disclaimer is scoped to Pekko's own
  guarantees, since TLS is delegated to the JDK's JSSE; and "message content is
  in scope" is scoped to defects in Pekko's handling of that content, not the
  application's interpretation of it, which §6 assigns to the application.

### Result

§14 holds two open questions, Q12 and Q13. Provenance moves to 41 documented /
43 maintainer / 4 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q12 assumed the failure detector and gossip convergence depend on clocks in a
way an adversary on a cluster member could exploit. Reading the code, they
largely do not, and the one place wall-clock time does cross nodes is already
documented on the type.

### Modification

**§14 Q12 - answered**, with the findings:

- The failure detector reads only the local clock
  (`FailureDetector.scala:60`, used at `PhiAccrualFailureDetector.scala:144`
  and `:188`). No remote timestamp reaches it.
- `Heartbeat.creationTimeNanos` is the sender's own `System.nanoTime()`
  (`ClusterHeartbeat.scala:130`), echoed back verbatim by the receiver
  (`:58`) and subtracted against the sender's own clock (`:251`). No node
  interprets another node's clock value, and the result feeds only a debug
  log guarded by `verboseHeartbeat`.
- Gossip ordering uses logical `VectorClock` counters
  (`VectorClock.scala:90-92`), with no wall-clock component.
- `LWWRegister` and `LWWMap` do merge by wall-clock timestamp across nodes.
  The requirement for synchronised clocks, and the alternatives, are stated in
  the `LWWRegister` scaladoc.

§5's clock assumption is rewritten to match: it previously implied a
dependency that the failure detector and gossip do not have.

### Result

§14 holds one open question, Q13. Provenance moves to 43 documented / 44
maintainer / 3 inferred.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q13 was the last open question. Classic remoting is deprecated but still
shipped and still CI-gated, and deprecation is not desupport.

### Modification

- **§14 Q13 - answered.** Security reports against classic remoting are
  accepted on the same terms as artery: configuration is the operator's per
  §5b, and implementation bugs will be looked at per §5b.4. Its §5a settings
  follow the same rulings as their artery equivalents.
- **§2** - the remoting row names classic remoting alongside artery, rather
  than describing the family as artery only.
- **§14** - retitled, since every question now carries a ruling. The section
  keeps the questions in place so the reasoning behind each answer stays
  visible and cross-references continue to resolve.

### Result

All thirteen questions are answered. Provenance moves to 43 documented / 48
maintainer / 3 inferred, the remaining three being the residual module in/out
split noted in §2 and Q6.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q10 recorded three documents each canonical for something, and noted that the
reporting wording was duplicated between `SECURITY.md` and the documentation
site's security index, which had already drifted apart once.

### Modification

`SECURITY.md` is now the strongest and canonical statement of the reporting
policy. Other documents link to it rather than restating it, and link to the
threat model for scope. Where another document carries a reporting statement
that `SECURITY.md` does not, it is referred to the maintainers to decide
whether to promote or drop it, rather than being migrated silently.

### Result

The reporting policy has one owner. The documentation-site page keeps
announcements and its index of security material.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

Q12 and §5 cited only the `LWWRegister` scaladoc for the synchronised-clock
requirement. The published documentation states it more fully, in the section
on `LWWMap` and again under `LWWRegister`, along with the custom `Clock` and
`reverseClock` alternatives.

### Modification

Both citations now name `typed/distributed-data.md` alongside the scaladoc.

### Result

The citation points where a reader would look first.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation

§5b makes §10 the operator's half of the contract: Pekko states what it does
not provide, and states what it expects instead. That only holds if §10 is
complete. Auditing it against `reference.conf` and the remoting documentation
found four obligations the model relies on but never stated, and two existing
items that were narrower than the code.

### Modification

Corrected:

- **10.4** - the `SECURITY` marker is not only the Java serializer's. The TLS
  providers use it to report a disabled hostname verification and surviving
  default keystore passwords, so the item now covers the marker rather than
  one emitter.
- **10.8** - environment substitution was only half the password obligation.
  Both SSL blocks ship `changeme` as the keystore, key and truststore password
  (`reference.conf:701`, `:1205`), and Pekko warns under the `SECURITY` marker
  if those survive into a running system.

Added:

- **10.10** - protect the key material itself. §6 trusts keystores, truststores
  and PEM material as operator-supplied; §10.5 scoped what a certificate grants
  but nothing stated the file-level counterpart.
- **10.11** - keep message-content logging off. `log-received-messages`,
  `log-sent-messages`, `pekko.actor.debug.receive` and `log-config-on-start`
  all default to `off`; turning any on moves payloads, or the secrets that
  §10.8 places in the environment, into the logging system.
- **10.12** - transport encryption exists only on `tls-tcp`. On `tcp` and
  `aeron-udp` network isolation is not one control among several, it is the
  only one.
- **10.13** - trust, or secure, the discovery mechanism. §6 marks resolver
  responses as potentially attacker-influenced; §10 asked nothing of the
  operator about it.

### Result

Every input §6 marks as trusted, and every §9 property Pekko disclaims, now has
a matching operator responsibility in §10.

### Tests

Not run - docs only

### References

Refs apache#3478
@pjfanning

Copy link
Copy Markdown
Member

I have pjfanning#59 - I'm not sure what the merge order is but feel free to comment on either PR>

pjfanning and others added 2 commits August 27, 2026 17:21
### Motivation

Q8 was recorded as "super-linear in message size is a bug" and routed to
`VALID`, which made a whole class of CPU reports security findings. That was
wider than intended, in two ways.

First, it conflated "a bug" with "a vulnerability". §5b.4 already provides for
defects Pekko fixes without their being security issues, and a performance
defect belongs there.

Second, the trigger did not match the intent. "Super-linear in message size"
fires on an ordinary message that is merely large, whereas the concern is an
input crafted so that cost explodes disproportionately to it.

### Modification

- **§14 Q8** - CPU cost is not in itself a security concern; a report of extra
  work or degraded throughput is a performance issue. The exception is
  disproportionate cost, where work grows super-linearly in the size or
  structure of a single input. The test is the cost, not the appearance of the
  input: an input that looks out of the ordinary is the usual sign of such a
  path rather than a separate condition. Constant-factor overhead is never a
  finding, and volume from an associated peer stays out of model per §7.
- **§6** - the size and rate note said the question was open. Frame-size limits
  and failure-detector bounds are recorded as tuning parameters, not security
  controls.
- **§9** - the resource-exhaustion entry carries the ruling rather than
  deferring to it.

### Result

Performance reports are triaged as performance, and only disproportionate cost
reaches a security disposition.

### Tests

Not run - docs only

### References

Refs apache#3478
### Motivation
The header still read "DRAFT - awaiting Pekko PMC review. Not yet
maintainer-ratified." That stopped being true once the PMC chair answered all
thirteen open questions: 48 of the document's claims now carry (maintainer)
provenance. A triager citing §9 to close a report should not be citing a
document that describes itself as unratified.

### Modification
- Status: replaced the draft banner with "Reviewed by the Apache Pekko PMC,
  2026-08-27", pointing at §14 for the rulings and naming the one item that is
  still open (the residual module in/out split, §2 and Q6).
- Renamed "Draft confidence" to "Provenance mix"; the counts and the
  explanation beneath it were already current and are unchanged.

No claim, ruling, citation or disposition is altered.

### Result
The document no longer disclaims its own authority. The single remaining
inferred item stays visible in the header rather than being smoothed over.

### Tests
Not run - docs only

### References
Refs apache#3478
@potiuk

potiuk commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Thanks @pjfanning — this is exactly what the draft was for, and considerably more
than I hoped for. Thirteen rulings, and the provenance moves from
40 documented / 0 maintainer / 14 inferred to 43 / 48 / 3.

Two of your commits correct me rather than extend me, and both are fair:
191e00d drops a scope ruling about app-bound sockets that I inferred and
shouldn't have, and 02066b0 restores the upstream-coordination wording in
SECURITY.md that I had paraphrased — I should have preserved that verbatim
rather than reworded it.

On merge order — your branch fast-forwarded cleanly from this one, so I've
pushed it here. All 19 of your commits are now on this PR with your authorship
intact; no rebase, no force push, nothing resolved by hand. That leaves a single
PR against apache/pekko carrying the full history, so
pjfanning#59 can be closed whenever suits you.

If you'd rather it went the other way round — yours opened against
apache/pekko and this one closed — that's equally fine and I'll close this.
It's your document now; I only wanted to avoid ending up with two.

I also pushed one small follow-up commit (9ed2a94): the header still read
Status: DRAFT — awaiting Pekko PMC review. Not yet maintainer-ratified, which
stopped being true once you answered the questions. A triager citing §9 to close
a report shouldn't be citing a document that calls itself unratified. It now
reads "Reviewed by the Apache Pekko PMC, 2026-08-27" and names the one item still
open. Two lines; no ruling, citation or disposition touched.

That open item is the last loose end: §2's module in/out split is still the ASF
Security team's proposal rather than a maintainer call, as Q6 notes. Not
blocking — worth a line from you at some point so the document has no inferred
claims left at all.

pjfanning added a commit that referenced this pull request Aug 27, 2026
…3479)

### Motivation

Both remoting transports log when TLS is enabled without hostname
verification, but at different levels. Artery logs at `warning`, classic
remoting at `info`, where it is easily lost in startup output. Both carry the
`LogMarker.Security` marker, which the documentation tells operators to treat
as security relevant, so the lower level in classic understates it.

### Modification

Log the classic remoting message at `warning`, matching artery. The message
text is unchanged, as is the `LogMarker.Security` marker.

### Result

Both transports report a disabled hostname verification at the same level.

### Tests

No test asserts on this message or its level.

### References

None - noticed while reviewing #3478
@pjfanning

Copy link
Copy Markdown
Member

Thanks @potiuk - I'll leave it open for review by others.

Comment thread THREAT_MODEL.md
- **"`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)*.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a very out-of-date recommendation (2014). Should we consider removing that from the doc entirely and from the security model?

@pjfanning pjfanning Aug 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread THREAT_MODEL.md

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`).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One JVM shutdown hook is registered by CoordinatedShutdown, as disclosed in §5; a shutdown hook is not a signal handler.

AI is also pointing me to the one below. Does it need to be mentioned?

if (system.settings.JvmShutdownHooks)
Runtime.getRuntime.addShutdownHook(shutdownHook)

@samueleresca

Copy link
Copy Markdown
Member

Should we advertise this PR in the committee mailing list for review?

@pjfanning

Copy link
Copy Markdown
Member

@samueleresca Can you send an email to the Dev mailing list? There are more people watching the GitHub repo but there might be some people only watching the list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants