This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
The following commit(s) were added to refs/heads/master by this push:
new fd9bdc9f8 docs: add security threat model + discoverability files
fd9bdc9f8 is described below
commit fd9bdc9f8571f8ac736dfc21ec0cef19e81e03c8
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Jul 28 09:30:50 2026 +0200
docs: add security threat model + discoverability files
Adds a v0 THREAT_MODEL.md (for the PMC to review, own, and merge)
plus AGENTS.md and SECURITY.md providing the conventional
AGENTS.md -> SECURITY.md -> THREAT_MODEL.md discoverability chain.
All three files are new and carry the ASF license header.
Generated-by: Claude Opus 4.8 (1M context)
* Fold in Szymon Janc's PMC review answers
Szymon reviewed the draft on 2026-07-24 and answered §14 Q1-Q14 inline.
The answers are folded into the body and retained in §14; the status
banner no longer claims the document is unreviewed.
Corrections to the draft:
- Tinycrypt support has been removed. The only supported crypto backend
is mbedTLS 3.6, with a move to the PSA crypto API planned. NimBLE
claims no constant-time or side-channel posture of its own; that rests
on the crypto library (§5a, §14 Q13).
- The RNG is not "the platform's" in the vague sense the draft assumed.
Host-side randomness comes from the controller via HCI LE Rand
(ble_hs_hci_rand()), which the Bluetooth spec requires to be
FIPS-compliant; LE SC code may use a platform TRNG directly where
configured; controller-side it is typically the SoC hardware RNG (§5).
- Bond/key persistence is outside core-host: it runs through callbacks
registered in ble_hs_cfg, so a backend may store keys in RAM, flash or
PSA. NimBLE ships one implementation (nimble/host/store/config); an
application may substitute its own. Store confidentiality is the
integrator's property (§5, §14 Q2).
- Only legacy pairing is enabled by default (nimble/host/syscfg.yml), so
LE Secure Connections is an opt-in (§5a).
- Direct Test Mode can be reachable in production if the application
allows it; it is compile-out-able but not compile-gated to test (§5a).
Sharpened for scan triage:
- Advertising data is passed to the application WITHOUT LTV inspection.
Helpers exist but applications are not obliged to use them, so AD
parsing safety is shared with the integrator (§6).
- Length fields are not guaranteed to stay within bounds on every layer
and must be checked, even though a peer must never write past the
provided buffer. Missing length validation on a radio-reachable path is
squarely in-model (§6, Q6).
- COC terminates on credit overflow; the ATT prepared-write queue is
bounded by BLE_ATT_SVR_MAX_PREP_ENTRIES and a timeout, with per-
attribute permissions (§6, Q10/Q11).
- Connection-flood / resource-exhaustion DoS is out of scope unless it is
an actual resource leak (§6, Q14).
- HCI is a trust boundary in split builds; Szymon rates such bugs low
severity except where a controller bug lets a remote peer crash the
host (Q1).
Still open: whether a silent security-level downgrade below what the
application requested is prevented (Szymon was not certain; the app does
receive an event on any security change), plus the meta questions Q15 and
Q16.
Generated-by: Claude Opus 5 (1M context)
---
AGENTS.md | 40 +++++
SECURITY.md | 43 ++++++
THREAT_MODEL.md | 472 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 555 insertions(+)
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..921548bd6
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,40 @@
+<!--
+#
+# 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.
+#
+-->
+
+# Agent guidance
+
+This file is read by automated agents (security scanners, code analyzers,
+AI assistants) operating on this repository. It points them at the
+human-authored references they should consult before producing output.
+
+## Security
+
+Security model: [SECURITY.md](./SECURITY.md), which links to the project's
+threat model at [THREAT_MODEL.md](./THREAT_MODEL.md).
+
+Apache NimBLE is a Bluetooth Low Energy (BLE) host + controller stack.
+Before reporting a security issue, consult `THREAT_MODEL.md`: most BLE
+traffic is unauthenticated by the Bluetooth specification (open
+advertising, pre-encryption traffic, and "Just Works" pairing has no MITM
+protection), and those spec-defined behaviours are not NimBLE defects. The
+in-model surface is memory safety in the radio PDU parsers (LL / HCI /
+L2CAP / ATT / SM) and the correctness of the Security Manager's pairing
+cryptography. See the §11a known-non-findings list.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..aaf4f182e
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,43 @@
+<!--
+#
+# 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.
+#
+-->
+
+# Security Policy
+
+## Reporting a Vulnerability
+
+Please report suspected security vulnerabilities privately to the Apache
+Security Team at <[email protected]>, following the ASF process at
+<https://www.apache.org/security/>. Do not open public GitHub issues or
+pull requests for security reports.
+
+## Threat Model
+
+Apache NimBLE's security threat model — its scope, trust boundaries (the
+graduated radio-trust tiers), the security properties it does and does not
+provide, the adversary model, and a list of recurring non-findings — is
+documented in [THREAT_MODEL.md](./THREAT_MODEL.md).
+
+Key point for triagers and scanners: a large part of BLE is unauthenticated
+by the Bluetooth specification (open advertising, traffic before encryption
+is established, and "Just Works" pairing, which provides no MITM
+protection). Those are spec-defined, not NimBLE bugs. The in-model surface
+is memory safety in the PDU parsers and the correctness of the Security
+Manager's cryptography. See `THREAT_MODEL.md` §9 and §11a.
diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
new file mode 100644
index 000000000..49f9cc841
--- /dev/null
+++ b/THREAT_MODEL.md
@@ -0,0 +1,472 @@
+<!--
+#
+# 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 NimBLE (mynewt-nimble) Security Threat Model (draft)
+
+> **Status: v0, reviewed by the PMC.** Drafted by the ASF Security team
+> from public artefacts (the in-repo source layout under `nimble/host`,
+> `nimble/controller`, `nimble/host/services`, and `syscfg.yml`) against
+> the Scovetta rubric, plus general Bluetooth-LE domain knowledge.
+> **Szymon Janc (Mynewt PMC) reviewed it on 2026-07-24** and answered
+> §14 Q1–Q14; those answers are folded into the body. Provenance tags:
+> *(documented)* / *(maintainer)* / *(inferred)*, with every load-bearing
+> *(inferred)* claim routed to a numbered §14 question. What remains
+> *(inferred)* is noted as still-open in §14.
+
+## §1 Header
+
+- **Project:** Apache NimBLE — a full Bluetooth Low Energy (BLE) host +
+ controller stack.
+- **Repository / commit:** `apache/mynewt-nimble`, `master` @ `793cb1612088`
(2026-06-09).
+- **Drafted:** 2026-06-13, ASF Security team (v0 draft from public artefacts).
+- **Companion repos this round:** `apache/mynewt-core` (the RTOS NimBLE
+ runs on, and which provides the management transport that may sit *on
+ top of* a BLE L2CAP channel) and `apache/mynewt-mcumgr` (uses a BLE
+ connection as one SMP transport — so NimBLE is the carrier, mcumgr the
+ payload).
+- **What triggers a revision:** a new Bluetooth spec feature
+ (new PDU types, a new pairing method, a new LL control procedure);
+ a change to the Security Manager's supported association models; a
+ change to the HCI host/controller split; or a new GATT service shipped
+ in-tree. Internal refactors that do not change a wire-facing parser or
+ the SM cryptography do not.
+
+## §2 Scope and intended use
+
+NimBLE is **the BLE protocol stack a firmware author links into a
+device**. It is not an application; it is the machinery that turns radio
+PDUs into connection/GATT events and back. It can be built as a
+**combined** host+controller, **host-only** (talking to an external
+controller over HCI), or **controller-only** (exposing HCI to an external
+host). *(documented: `nimble/{host,controller,transport}` layout; §14 Q1)*
+
+### Component families (each at its own trust/surface tier)
+
+| Family | Source | What it parses / does | Radio-trust tier |
+| --- | --- | --- | --- |
+| **Controller / Link Layer (LL)** | `nimble/controller/src/ble_ll_*` | Lowest
level: advertising, scanning, connection establishment, LL control PDUs,
channel selection, encryption (`ble_ll_crypto`), RPA resolution, whitelist,
DTM. | **Tier 0 — raw radio.** Processes PDUs from *anyone in range* before any
connection or authentication exists. |
+| **HCI transport** | `nimble/transport`, `ble_hs_hci*`, `ble_ll_hci*` | The
command/event boundary between host and controller. | Boundary **only when
split**; in a combined build it is internal. |
+| **Host — L2CAP** | `ble_l2cap*` (+ `_coc`, `_sig`) | Channel multiplexing,
fragmentation/reassembly, connection-oriented channels, signalling. | **Tier 1
— connected peer**, pre- or post-encryption. |
+| **Host — ATT / GATT** | `ble_att*`, `ble_gattc`, `ble_gatts` | The attribute
protocol server/client and GATT layer above it. | Tier 1; the server parses
every ATT request from the peer. |
+| **Host — GAP + advertising data** | `ble_gap`, `ble_hs_adv` |
Connection/advertisement state machine; parses advertising/scan-response data.
| Tier 0/1. |
+| **Security Manager (SM)** | `ble_sm`, `ble_sm_sc`, `ble_sm_lgcy`,
`ble_sm_alg`, `ble_sm_cmd` | Pairing, key generation, MITM protection, LE
Secure Connections (ECDH P-256) and legacy pairing. **This is where NimBLE's
actual security *properties* live.** | Tier 1; pairing PDUs are
attacker-reachable; the *output* is the encryption/authentication of the link. |
+| **Privacy** | `ble_hs_pvcy`, `ble_ll_resolv` | Resolvable Private Address
(RPA) generation/resolution. | Tier 0. |
+| **In-tree GATT services** |
`nimble/host/services/{ans,bas,bleuart,dis,gap,ias,ipss,lls,tps}` |
Example/standard GATT services. | Application-tier; mostly demo/standard
profiles (§3). |
+
+### What NimBLE is *not*
+
+- Not the application's GATT logic. NimBLE provides the protocol and the
+ *mechanism* to require encryption/authentication on a characteristic;
+ **which** characteristics require it is the application's choice (§10).
+- Not the radio PHY or the RF hardware (`drivers/` are thin HW shims).
+- Not key storage at rest — bond/key persistence uses the host OS's store
+ (`apache/mynewt-core` or the porting layer). *(inferred — §14 Q2)*
+
+## §3 Out of scope (explicit non-goals)
+
+1. **Application GATT services and their access-control choices.** If an
+ app exposes a sensitive characteristic with no encryption/auth
+ requirement, that is the app's decision, not a NimBLE defect (§10).
+ The in-tree `host/services/*` are standard/demo profiles in this same
+ category.
+2. **The Bluetooth specification itself.** Where the spec mandates an
+ unauthenticated or weak-by-modern-standards behaviour (open
+ advertising, passive-eavesdroppable pre-encryption traffic, "Just
+ Works" pairing with no MITM protection, legacy pairing), NimBLE
+ conforming to the spec is **not** a NimBLE vulnerability (§11a).
+3. **The radio PHY / RF front-end / hardware** and the timing of the
+ link — jamming, RF interference, and physical-layer attacks are out.
+4. **The host RTOS, its scheduler, and key-at-rest storage** — modelled
+ in `apache/mynewt-core` / the porting layer.
+5. **mcumgr / newtmgr management payloads** that *ride on top of* a BLE
+ L2CAP channel — NimBLE is the carrier; the SMP server is modelled in
+ `apache/mynewt-mcumgr` and `apache/mynewt-core`'s `mgmt/`.
+6. **Physical / invasive and side-channel attacks** on the device.
+7. **Supply-chain / build hygiene.**
+
+## §4 Trust boundaries and data flow
+
+The trust boundary is **the antenna**. What differs from a wired stack is
+that there are **graduated** radio-trust tiers, and the same code base
+processes input at every tier:
+
+```
+ Tier 0 RAW RADIO (anyone in range, NO connection, NO auth)
+ adv / scan-req / scan-rsp / connect-ind / LL-control PDUs
+ | ble_ll_* (controller) ble_hs_adv (host, adv-data parse)
+ v
+ Tier 1 CONNECTED PEER (a link exists; may be UNENCRYPTED)
+ L2CAP (+reassembly) -> ATT requests -> GATT ; SM pairing PDUs
+ | ble_l2cap* / ble_att_svr / ble_sm*
+ v
+ [ Security Manager pairing ] --(if an *authenticated* method used)-->
+ v
+ Tier 2 ENCRYPTED + (optionally) AUTHENTICATED LINK
+ AES-CCM link encryption (ble_ll_crypto) ; bonded keys
+ |
+ v
+ application GATT characteristics (permissions are the APP's choice, §10)
+
+ HCI boundary (only in split host/controller builds):
+ host <== HCI events/ACL ==> controller (trusted in combined builds)
+```
+
+Two consequences: (1) **most NimBLE code runs at Tier 0/1 against fully
+untrusted input** — memory safety there is the core obligation; (2) the
+*transition* from Tier 1 to Tier 2 **is** NimBLE's security product — the
+correctness of the Security Manager's pairing crypto is what authenticates
+and encrypts the link.
+
+## §5 Assumptions about the environment
+
+- **Embedded, single address space, no MMU/process isolation.** A
+ memory-safety bug in any PDU parser is a whole-device compromise.
+ *(inferred — §14 Q3)*
+- **In a combined build, host and controller trust each other** over the
+ internal HCI; in a split build, the HCI transport is itself a trust
+ boundary and each side must tolerate a malformed/ hostile peer across
+ it. *(inferred — §14 Q1)*
+- **The RNG is the Bluetooth controller's**, not NimBLE's. On the host
+ side randomness comes from the HCI `LE Rand` command
+ (`ble_hs_hci_rand()`, `nimble/host/src/ble_hs_hci_util.c`), which the
+ Bluetooth specification requires to be FIPS-compliant; parts of the LE
+ SC algorithm code may use a platform TRNG directly where configured to.
+ On the controller side this typically sources the SoC's hardware RNG.
+ Its quality is therefore **the controller/SoC's** property, backed by
+ the spec — not something NimBLE implements. *(maintainer — §14 Q4)*
+- **Bond/key storage is the integrator's, not NimBLE's.** Persistence
+ happens through callbacks registered in `ble_hs_cfg`, so the backend may
+ keep keys in RAM, flash, PSA, or anywhere else. NimBLE ships one
+ implementation (`nimble/host/store/config`, on Mynewt `sys/config`);
+ applications may substitute their own. Confidentiality and integrity of
+ that store are assumed, and are **outside** core-host.
+ *(maintainer — §14 Q2)*
+
+## §5a Build-time and configuration variants
+
+- **Role build (combined / host-only / controller-only)** changes which
+ parsers are present and whether HCI is a boundary. *(documented: layout)*
+- **Supported pairing methods / SM features** are syscfg-selectable
+ (LE Secure Connections vs legacy, bonding, MITM, OOB, key-distribution
+ set). The *security posture of the link depends on which are enabled
+ and which the application requests.* **By default only legacy pairing
+ is enabled** (`nimble/host/syscfg.yml`) — so a build that wants LE
+ Secure Connections must turn it on deliberately.
+ *(maintainer — §14 Q5)*
+- **Crypto backend.** Tinycrypt support was **removed**; the only
+ supported backend is **mbedTLS 3.6**. A move to the PSA crypto API is
+ planned. NimBLE claims no constant-time / side-channel posture of its
+ own — that rests on the crypto library. *(maintainer — §14 Q13)*
+- **Privacy (RPA)** on/off and the resolving-list size. *(documented:
+ `ble_hs_pvcy`, `ble_ll_resolv`)*
+- **Maximum MTU / number of connections / L2CAP COC buffers** bound
+ reassembly and allocation. *(inferred — §14 Q6)*
+- **Direct Test Mode (`ble_ll_dtm`)** is a radio-hardware test feature,
+ typically used in test labs for emission approval. It is a controller
+ feature with a thin host layer for application access. It **can be
+ compiled out, and it can also be reachable in production if the
+ application allows it** — so its presence is a per-build integrator
+ decision rather than something the library forces either way.
+ *(maintainer — §14 Q7)*
+
+## §6 Assumptions about inputs
+
+**Every radio PDU is attacker-controllable** to anyone within range. The
+question for each surface is only *which tier* it is reachable at.
+
+### Radio-input trust table
+
+| Surface | Source code | Reachable by | Must enforce |
+| --- | --- | --- | --- |
+| Advertising / scan-response **data** | `ble_hs_adv`, `ble_ll_adv`,
`ble_ll_scan` | anyone in range, no connection | memory-safe parse of
arbitrary/truncated/over-length AD structures; no OOB on malformed length
fields. **NimBLE ignores/rejects malformed PDUs, but passes advertising data up
to the application WITHOUT LTV inspection** — parsing helpers exist, the
application is not obliged to use them. So AD-parsing safety is shared with the
integrator *(maintainer — §14 Q8)* |
+| `connect-ind` / connection setup | `ble_ll_conn`, `ble_gap` | anyone in
range | bounded state allocation; safe handling of malformed connection
parameters *(inferred — §14 Q8)* |
+| **LL control PDUs** | `ble_ll_ctrl` | a connected peer (Tier 1,
pre-encryption) | safe handling of every control opcode incl.
length/feature/PHY-update, version, and **encryption-start** procedures
*(inferred — §14 Q9)* |
+| HCI commands/events | `ble_ll_hci*`, `ble_hs_hci*` | the HCI peer (split
build) or internal | length/parameter validation on every event/command
*(inferred — §14 Q1)* |
+| **L2CAP** packets + reassembly | `ble_l2cap`, `_coc`, `_sig` | connected
peer | reassembly bounds (no overflow on a lying L2CAP length); COC credit/flow
safety *(inferred — §14 Q10)* |
+| **ATT requests** | `ble_att_svr` | connected peer (pre/post-encryption per
char permission) | bounds on every ATT opcode (READ/WRITE/PREPARE-WRITE queue,
FIND, READ-BLOB offset); the prepared-write queue is a classic resource sink
*(inferred — §14 Q11)* |
+| **SM pairing PDUs** | `ble_sm*` | connected peer, pre-encryption | correct
pairing state machine; **validate the peer's ECDH public key** (reject
invalid-curve / zero / debug keys); no key/nonce reuse; constant-time where it
matters *(inferred — §14 Q12, the highest-value crypto question)* |
+
+### Size / shape / rate
+
+- Reassembly and allocation are bounded by the **configured memory pools**
+ — `msys` or a dedicated pool (§5a). **Regardless of configuration, a
+ peer must not be able to write past the provided buffer.** But note the
+ maintainer's caveat: *depending on the layer or protocol, length fields
+ are not guaranteed to stay within bounds and must be checked.* Missing
+ length validation on a radio-reachable path is therefore squarely
+ in-model. *(maintainer — §14 Q6)*
+- **L2CAP COC:** if a peer sends more packets than its credits allow, the
+ channel is terminated. *(maintainer — §14 Q10)*
+- **ATT prepared-write queue:** bounded by a configurable limit and a
+ timeout, after which the connection is terminated and resources freed
+ (`BLE_ATT_SVR_MAX_PREP_ENTRIES`, `BLE_ATT_SVR_QUEUED_WRITE_TMO`).
+ Permissions are enforced **per attribute**. *(maintainer — §14 Q11)*
+- No rate guarantee against a flooding/jamming peer (§9). Connection-flood
+ and resource-exhaustion DoS is **out of scope unless it is an actual
+ resource leak** — it depends on system configuration and application
+ policy. *(maintainer — §14 Q14)*
+
+## §7 Adversary model
+
+### Actors
+
+| Actor | In scope? | Capabilities |
+| --- | --- | --- |
+| **Anyone in radio range** | **yes — primary** | passively sniff all
pre-encryption traffic; inject/spoof advertising; initiate connections; send
malformed PDUs at every layer; attempt/abort pairing; replay. |
+| **Active MITM during pairing** | **yes** | sit between two pairing devices.
NimBLE's defence is an *authenticated* SM association model (Passkey / Numeric
Comparison / OOB); "Just Works" provides **none** by spec (§9, §11a). |
+| **A bonded/paired peer turned malicious** | **conditionally** | has a valid
LTK; can send well-formed encrypted requests. In-model only for memory safety /
bounds in the request parsers — not for "a bonded peer can use the services it
was granted." |
+| **HCI peer** (split builds) | **yes** | a malicious external controller/host
across the HCI transport. |
+| **Application firmware author** | **out of scope** | trusted; chooses
pairing requirements and characteristic permissions. |
+| **Physical / RF-layer attacker** (jam, glitch, decap) | **out of scope** |
§3.3, §3.6. |
+| **Side-channel observer** of SM crypto | **partially — §14 Q13** |
timing/DPA on pairing; NimBLE's constant-time posture is unconfirmed. |
+
+### The graduated-trust asymmetry
+
+Unlike a wired protocol, **most BLE traffic is unauthenticated by spec**
+up to the moment pairing completes. The adversary's reach is therefore
+huge at Tiers 0/1 and is *reduced* only by (a) NimBLE's parser robustness
+and (b) the application requiring an authenticated pairing before
+exposing anything sensitive. A finding that "an unpaired peer can read
+characteristic X" is the *application's* permission choice (§10), not a
+NimBLE bug — **unless** NimBLE failed to enforce a permission the app
+*did* set, which is VALID.
+
+## §8 Security properties the project provides
+
+For each: condition, violation symptom, severity, provenance.
+
+1. **Memory-safe parsing of malformed PDUs across LL / HCI / L2CAP /
+ ATT / SM**, given a correct platform. *(inferred — §14 Q8–Q12; the
+ foundational property)*
+ - *Violation:* a crafted PDU (bad length, malformed AD, oversized ATT
+ write, lying L2CAP reassembly length) → OOB read/write or overflow.
+ - *Severity:* **high** (single address space; reachable by anyone in
+ range, pre-authentication).
+2. **Correct LE Secure Connections pairing** — ECDH P-256 with peer
+ public-key validation, MITM protection under authenticated association
+ models, fresh nonces, correct key derivation. *(inferred — §14 Q12)*
+ - *Violation:* accepting an invalid/zero/debug ECDH key, nonce reuse,
+ or a downgrade that silently drops MITM protection the app required.
+ - *Severity:* **high** (breaks the security NimBLE exists to provide).
+3. **Correct AES-CCM link encryption** once a key is established
+ (`ble_ll_crypto`). *(inferred — §14 Q9)*
+ - *Violation:* keystream/nonce reuse, encryption not actually applied
+ after the start-encryption procedure.
+ - *Severity:* **high**.
+4. **Enforcement of the ATT permission the application set** on a
+ characteristic (require-encryption / require-authentication). *(inferred
+ — §14 Q11)*
+ - *Violation:* serving a read/write on an encryption-required attribute
+ over an unencrypted link.
+ - *Severity:* **high**.
+5. **Address privacy via RPA** when enabled. *(documented: `ble_hs_pvcy`)*
+ - *Violation:* a static identifier leaking despite RPA being on.
+ - *Severity:* **medium**.
+
+## §9 Security properties the project does *not* provide
+
+- **No security for unauthenticated association ("Just Works") pairing.**
+ By spec, Just Works has **no MITM protection**; an active MITM can pair
+ with both sides. The application must *choose* an authenticated method
+ (Passkey / Numeric Comparison / OOB) for sensitive use. *(spec-defined;
+ §11a)*
+- **No confidentiality before encryption is established.** All Tier 0/1
+ traffic is sniffable. *(spec-defined)*
+- **No protection against jamming / RF DoS / connection flooding.**
+ *(inferred — §14 Q14)*
+- **No app-layer access control.** NimBLE enforces the *char permission
+ the app set*; it does not decide policy. A characteristic the app left
+ open is open by the app's choice. *(inferred — §14 Q11)*
+- **No defence against a legitimately-bonded peer** doing what its bond
+ permits. *(inferred)*
+- **No guarantee about legacy pairing strength** — legacy pairing is weak
+ by modern standards; use LE Secure Connections. *(spec-defined; §11a)*
+- **No constant-time / side-channel guarantee** on SM crypto unless
+ confirmed. *(inferred — §14 Q13)*
+
+### False friends
+
+- **"Paired" ≠ "authenticated."** A Just-Works bond is *paired* but not
+ *MITM-protected*. The `authenticated` flag on the bond is the property
+ that matters.
+- **"Connected" ≠ "authorized."** Anyone in range can connect; access to
+ data is gated by ATT permissions, not by the existence of a connection.
+- **A resolvable private address still resolves** for a peer holding the
+ IRK — RPA defeats *tracking by third parties*, not identification by a
+ bonded peer.
+
+## §10 Downstream responsibilities
+
+1. **Require an authenticated pairing method** (Passkey / Numeric
+ Comparison / OOB) before exposing anything sensitive — do not rely on
+ Just Works for confidential or safety-relevant data.
+2. **Set ATT characteristic permissions correctly** — mark sensitive
+ characteristics require-encryption and/or require-authentication.
+3. **Prefer LE Secure Connections; disable legacy pairing** where the
+ threat model needs modern guarantees.
+4. **Enable privacy (RPA)** if device tracking is a concern.
+5. **Provision a strong platform RNG** and confidential bond storage.
+6. **Keep test features (DTM) out of production** builds.
+
+## §11 Known misuse patterns
+
+- Using **Just Works** pairing for sensitive data and assuming it
+ protects against MITM.
+- Exposing sensitive GATT characteristics with **no encryption/auth
+ permission** and assuming "you need our app to connect."
+- Assuming **advertising is private** or that a static address is not
+ trackable (use RPA).
+- Relying on **legacy pairing** for modern confidentiality.
+- Shipping with **Direct Test Mode** reachable.
+- Treating a **connection** as if it were authorization.
+
+## §11a Known non-findings (recurring false positives)
+
+| Reported as | Why it is a non-finding | Cite |
+| --- | --- | --- |
+| "Device advertises / is connectable without authentication" | BLE
advertising and connection establishment are unauthenticated *by spec*; data
access is gated by ATT permissions, not by connecting. | §3.2, §9 |
+| "Just Works pairing has no MITM protection" | True and *spec-defined*; the
application must select an authenticated association model. Not a NimBLE
defect. | §9, §10.1 |
+| "Traffic is sniffable before encryption" | Spec-defined; confidentiality
begins after the encryption-start procedure. | §9 |
+| "Legacy pairing is cryptographically weak" | Spec property of legacy
pairing; remediation is to require LE Secure Connections (which NimBLE
supports). | §9, §10.3 |
+| "A peer can reset/flood/jam the link (DoS)" | No availability guarantee
against an in-range RF adversary is claimed. | §9 |
+| "Static/public BD address is trackable" | RPA exists for exactly this; if
disabled, that is the integrator's choice. | §9, §10.4 |
+| "Characteristic X is readable by an unpaired peer" | That is the
application's ATT-permission choice, not a NimBLE bug — *unless* NimBLE failed
to enforce a permission that **was** set (then VALID). | §9, §10.2 |
+| "ECDH debug keys accepted in test build" | Debug keys are a spec test
feature; relevant only if reachable in a production build (→ §14 Q12). | §5a,
§14 Q12 |
+
+The discriminator: anything resting on **"BLE/this pairing mode is
+unauthenticated"** is spec, not bug. A **memory-safety/bounds failure in
+a parser**, or a **crypto/state-machine error that breaks a guarantee
+NimBLE *does* claim (SM key validation, encryption actually applied,
+enforcing an app-set permission)**, is VALID.
+
+## §12 Conditions that would change this model
+
+- A new pairing/association model or SM feature.
+- A change to host/controller split or HCI handling.
+- A new LL control procedure or PDU type from a spec update.
+- Moving key storage in-tree, or taking ownership of the platform RNG.
+- A new in-tree service that is more than a standard/demo profile.
+
+## §13 Triage dispositions
+
+| Disposition | Use when |
+| --- | --- |
+| **VALID** | Memory-unsafety/bounds failure in any LL/HCI/L2CAP/ATT/SM parser
reachable from the radio; SM cryptographic/state-machine error (bad ECDH key
accepted, nonce/key reuse, silent MITM-downgrade); encryption not applied after
start; failure to enforce an ATT permission the app set. |
+| **OUT-OF-MODEL** | The report depends on a spec-defined unauthenticated/weak
behaviour (open advertising, Just Works, pre-encryption sniffing, legacy
pairing) — §9. |
+| **DOWNSTREAM** | Fix is the integrator's: require authenticated pairing, set
char permissions, enable RPA, disable legacy/DTM (§10). |
+| **NON-FINDING** | Matches a §11a row. |
+| **MODEL-GAP** | In-scope in spirit but no §8/§9 item covers it → §14. |
+
+## §14 Open questions for the maintainers
+
+**Answered by Szymon Janc (Mynewt PMC) on 2026-07-24**, in review of the
+PR that introduced this document. Q1–Q14 are answered below and folded
+into the body above.
+
+**Build / architecture — ANSWERED**
+- **Q1.** Is the HCI transport a trust boundary in split host/controller
+ builds? → **Yes, treat it as a boundary** — a bug on one side should
+ not affect the other. Szymon rates such issues **low severity** in
+ practice, with the notable exception of a controller bug that lets a
+ remote peer crash the host (e.g. during an LL procedure).
+- **Q2.** Where do bonds/keys persist? → **Outside "core-host."**
+ Persistence is done by callbacks registered in `ble_hs_cfg` (the host's
+ main configuration struct), so the backend may store keys anywhere —
+ RAM, flash, PSA. NimBLE ships one implementation in
+ `nimble/host/store/config` (built on Mynewt `sys/config`, RAM or
+ flash); an application may supply its own platform-specific one.
+ **Key-store confidentiality is therefore the integrator's property, not
+ NimBLE's.**
+- **Q3.** Single-address-space / no-isolation amplification. →
+ **Confirmed** in general; it depends on platform configuration.
+
+**Crypto / Security Manager — ANSWERED**
+- **Q4.** What RNG do SM/ECDH/RPA consume? → **The Bluetooth
+ controller's**, on the host side via the HCI `LE Rand` command
+ (`ble_hs_hci_rand()` in `nimble/host/src/ble_hs_hci_util.c`). The
+ Bluetooth specification requires that command be FIPS-compliant. Parts
+ of the LE SC algorithm code may use a platform TRNG directly where so
+ configured. On the controller side this typically sources the SoC's
+ hardware RNG peripheral, which is spec-compliant. So RNG quality rests
+ on **the controller/SoC and the spec**, not on NimBLE code.
+- **Q5.** Which SM association models are enabled by default, and is
+ silent downgrade prevented? → **Only legacy pairing is enabled by
+ default** (`nimble/host/syscfg.yml`). Szymon was **not certain** about
+ silent security-level-downgrade prevention; he notes the application
+ always receives a proper event when security changes. *(the downgrade
+ question therefore stays partly open — see below)*
+- **Q12.** Does `ble_sm_sc` validate the peer's ECDH public key and are
+ nonces fresh? → **Yes.**
+- **Q13.** Constant-time / side-channel posture for SM operations? →
+ **None claimed by NimBLE — it relies on the crypto library.** Tinycrypt
+ support was **recently removed**; the only supported backend now is
+ **mbedTLS 3.6**. There are plans to move to the PSA crypto API.
+
+**Parser robustness — ANSWERED**
+- **Q6.** What bounds reassembly/allocation? → **Configured memory pools**
+ (`msys` or a dedicated pool). Regardless of configuration, **a peer must
+ not be able to write past the provided buffer**; but depending on the
+ layer or protocol, **length fields are not guaranteed to stay within
+ bounds and must be checked**. That makes length-field validation a
+ first-order review target.
+- **Q8.** Robustness target for malformed advertising data / connection
+ PDUs? → **Ignore or reject them.** Note: **advertising data is passed to
+ the application without LTV inspection.** Parsing helpers are provided,
+ but the application is not obliged to use them and may parse on its own
+ — so malformed-AD handling is partly the integrator's.
+- **Q9.** Handling of LL control opcodes? → **Ignore or reject invalid
+ PDUs**, likewise unexpected or out-of-order ones; depending on the
+ spec-defined procedure this may involve link termination.
+- **Q10.** L2CAP reassembly and COC credit/flow bounds? → **If a peer
+ overflows** — sends more packets than its credits allow — **the COC is
+ terminated.**
+- **Q11.** Does `ble_att_svr` enforce per-attribute permissions, and what
+ bounds the prepared-write queue? → **Permissions are per attribute.**
+ The prepared-write queue has a **configurable limit and a timeout**,
+ after which the connection is terminated and resources freed
+ (`BLE_ATT_SVR_MAX_PREP_ENTRIES`, `BLE_ATT_SVR_QUEUED_WRITE_TMO` in
+ `nimble/host/syscfg.yml`).
+
+**Features — ANSWERED**
+- **Q7.** Is `ble_ll_dtm` (Direct Test Mode) reachable in production? →
+ **It can be.** It is a radio-HW test mode (used in test labs for
+ emission approvals), a controller feature with a thin host layer for
+ application access. It **may or may not** be enabled in production and
+ **can be compiled out** — reachable in production if the application
+ allows it.
+- **Q14.** Posture on connection-flood / resource-exhaustion DoS? →
+ **Out of scope**, unless there is an actual resource *leak*. It depends
+ wholly on system configuration and application policy.
+
+**Still open**
+- **Q5a.** Whether NimBLE prevents a *silent* security-level downgrade
+ below what the application requested. Szymon was not certain; the
+ application does get an event on any security change.
+- **Q15 / Q16** (meta / `host/services/*` scoping) — not yet answered.
+
+## Appendix: existing security-policy artefacts → §x back-map
+
+At `master @ 793cb1612088`, `apache/mynewt-nimble` contains **no
+`SECURITY.md`, `AGENTS.md`, or prior threat-model document**. The
+`nimble/doc` and `qualification/` trees are Bluetooth-qualification and
+API documentation, not a security policy. This is a greenfield v0; there
+is nothing to supersede or back-map. Source-layout facts are cited inline
+as *(documented)*.