# Phase 1 — Dependency Scan

**Scan date**: 2026-05-19
**Tool**: `pip-audit` 2.10.0 (PyPI advisory DB + OSV.dev)
**Method**: `pip-audit --strict --requirement <filtered freeze>` against the project's `.venv` (Python 3.10.8). The editable `gps-denied-onboard==0.1.0` root distribution was excluded from the audited set — pip-audit cannot audit non-PyPI editable installs.
**Manifest**: `pyproject.toml` (sole manifest — no `requirements*.txt`, no `Cargo.toml`, no `package.json`, no `*.csproj`, no `go.mod`).
**Audited**: 94 third-party distributions (production + dev + inference + telemetry extras as installed in `.venv`).
**Excluded**: the project itself (`gps-denied-onboard==0.1.0`); TensorRT (installed out-of-band on Jetson per `pyproject.toml` line 123, not a pip dep, audited via on-device SBOM at deploy time).

## Findings

12 advisories across 5 packages. **0 are Critical; 0 are High in this project's threat model** (per the per-finding impact analysis in § Project-Specific Triage). The single Medium is `cryptography` CVE-2026-39892 (only triggered by non-contiguous Python buffers — see triage).

| # | Severity (this project) | Package | Installed | CVE / Advisory | Fix Version | Title |
|---|---|---|---|---|---|---|
| F1 | **Medium** | `cryptography` | 45.0.7 | CVE-2026-39892 (GHSA-p423-j2cm-9vmq) | 46.0.7 | `Hash.update()` buffer overflow on non-contiguous Python buffers (Python >3.11) |
| F2 | Low | `cryptography` | 45.0.7 | CVE-2026-26007 (GHSA-r6ph-v2qm-q3c2) | 46.0.5 | ECDH/ECDSA public-key not validated against small-order subgroup (SECT curves only) |
| F3 | Low | `cryptography` | 45.0.7 | CVE-2026-34073 (GHSA-m959-cc7f-wv43) | 46.0.6 | DNS-name constraint validation gap between SAN and peer-name (Web PKI bypass; requires uncommon X.509 topology) |
| F4 | Low | `starlette` | 0.48.0 | CVE-2025-62727 (GHSA-7f5h-v6xp-fcq8) | 0.49.1 | `FileResponse._parse_range_header` ReDoS via crafted `Range` header (O(n²) merge) |
| F5 | Low | `idna` | 3.14 | CVE-2026-45409 (GHSA-65pc-fj4g-8rjx) | 3.15 | `idna.encode()` DoS via overlong inputs (re-fix of CVE-2024-3651) |
| F6 | Low | `paramiko` | 3.5.1 | CVE-2026-44405 (GHSA-r374-rxx8-8654) | _(no fix released)_ | `rsakey.py` allows SHA-1 algorithm |
| F7 | Low | `pillow` | 11.3.0 | CVE-2026-25990 (GHSA-cfh3-3jmp-rvhc) | 12.1.1 | PSD image out-of-bounds write |
| F8 | Low | `pillow` | 11.3.0 | CVE-2026-40192 (GHSA-whj4-6x5x-4v2j) | 12.2.0 | FITS decompression bomb (unbounded memory) |
| F9 | Low | `pillow` | 11.3.0 | CVE-2026-42308 (GHSA-wjx4-4jcj-g98j) | 12.2.0 | Font glyph advance integer overflow |
| F10 | Low | `pillow` | 11.3.0 | CVE-2026-42309 (GHSA-5xmw-vc9v-4wf2) | 12.2.0 | Nested-list coordinate heap buffer overflow in `ImagePath.Path` / `ImageDraw.polygon` |
| F11 | Low | `pillow` | 11.3.0 | CVE-2026-42310 (GHSA-r73j-pqj5-w3x7) | 12.2.0 | PDF parser infinite loop on cyclic `Prev` pointers (100% CPU hang) |
| F12 | Low | `pillow` | 11.3.0 | CVE-2026-42311 (GHSA-pwv6-vv43-88gr) | 12.2.0 | PSD memory corruption via integer overflow in tile-extent bounds check (regression of CVE-2026-25990 fix in 12.1.1) |

## Project-Specific Triage

The "Severity (this project)" column above reflects the **actual exposure** in this codebase, not the advisory's generic CVSS score. The same advisory can be High in a public-facing web app and Low here when the affected code path is unreachable.

### F1 — `cryptography` CVE-2026-39892 (Medium)

Buffer overflow when a non-contiguous Python buffer is passed to `Hash.update()` on Python > 3.11. **The project's `requires-python = ">=3.10,<3.12"` (`pyproject.toml` line 10) currently caps Python at 3.11.x — Python 3.12 is intentionally excluded.** Today's deployment is therefore not exposed. The finding is kept at Medium (rather than Low) because:

- Upstream `cryptography` and `gtsam` will eventually drop the Python-3.11 cap (gtsam-4.2 ABI bind to numpy 1.x is what holds us back — see `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`); when that happens, this CVE re-exposes unless `cryptography` is also bumped.
- C10 `ManifestBuilder` (AZ-323) and C11 signing-key (AZ-318) build Ed25519 hash inputs via `cryptography.hazmat.primitives.hashes`. The current code path uses standard `bytes`, but a future refactor that touches `memoryview` or sliced inputs could regress.

**Action**: pin `cryptography>=46.0.7` once the Python ≥ 3.12 cap is lifted (couple it to the Python-cap bump). Document the constraint in `_docs/_process_leftovers/` so it doesn't get lost.

### F2 — `cryptography` CVE-2026-26007 (Low)

SECT (Koblitz) curves only. Project's signing path is Ed25519 (`cryptography.hazmat.primitives.asymmetric.ed25519`, AZ-318 / AZ-323); SECT curves are never instantiated. **Not exposed.**

### F3 — `cryptography` CVE-2026-34073 (Low)

DNS name-constraint validation gap during X.509 path validation. Project does NOT perform custom X.509 validation — TLS validation is handled by the standard `httpx` / `requests` paths against the operating system / `certifi` trust store. The Suite Satellite Service contract (D-PROJ-2) is HTTPS to a single mTLS-pinned host; no name-constraint extensions are in play. **Not exposed.**

### F4 — `starlette` CVE-2025-62727 (Low)

ReDoS in `FileResponse._parse_range_header`. Project surface:
- `e2e/fixtures/mock-suite-sat/` is a FastAPI/starlette app (test fixture, lives inside its own Docker image — never deployed to production).
- The mock's runtime container is on the `e2e-net` Docker network with `internal: true` (no external reachability per RESTRICT-SAT-1 / NFT-SEC-02).
- The mock does not serve `FileResponse` or `StaticFiles` — it's a JSON-only POST/GET stub. The `_parse_range_header` code path is unreachable from the mock's routes.

**Not exposed in production** (FastAPI/starlette never ship in the airborne binary; they're test-only dev extras per `pyproject.toml` lines 95-118). **Test isolation prevents exposure even in CI.** Recommended action: bump `fastapi` test-time pin upward when the next compatible release lands; no production action required.

### F5 — `idna` CVE-2026-45409 (Low)

`idna.encode()` DoS via overlong inputs. Project imports idna transitively via `requests` / `httpx`. The only outbound HTTP/HTTPS path in production is C11 `TileUploader` → `satellite-provider` (single trusted host, hostname fixed at compile time) and C12 `FlightsApiClient` → operator GCS (single trusted host). **No remote-controlled hostnames are encoded** — IDN resource exhaustion requires attacker-controlled domain strings. **Not exposed.**

### F6 — `paramiko` CVE-2026-44405 (Low)

SHA-1 still allowed for RSA host-key signatures. Project surface: C12 `CompanionBringup` (AZ-327, `pyproject.toml` line 92) uses paramiko to SSH the operator's companion before flight for artifact verification. Host keys are pinned per-operator (no `AutoAddPolicy` in production — `MissingHostKeyPolicy=RejectPolicy`). SHA-1 RSA host keys could still be accepted, but:
- The threat is MitM between operator workstation and companion on a network the operator already controls.
- All operator companions are pinned by host-key fingerprint at provisioning time (D-C12-7).

**Not actively exploitable in the deployed model.** Watch for an upstream fix; bump when one lands.

### F7-F12 — `pillow` 6× CVEs (Low, test-only)

All pillow CVEs touch image formats (PSD, FITS, PDF) and APIs (`ImagePath.Path`, `ImageDraw.polygon`) that the SUT does NOT use. Project surface:
- `pyproject.toml` declares Pillow as a **test-only** dev dep (lines 109-117): "the production builder runs inside its own Docker image (which installs Pillow itself); this Pillow pin is only the test-time dep used by `e2e/_unit_tests/fixtures/test_tile_cache_builder.py`."
- The production SUT image (`docker/Dockerfile`) does NOT install Pillow as a runtime dep; OpenCV (`opencv-python`) is the sole image-decoder pathway.
- The test-time consumer only handles **paired `_gmaps.png` reference images and stub tiles emitted by the project itself** — no untrusted PSD/FITS/PDF inputs.

**Not exposed in production. Not exposed in CI** (test inputs are local-data-only fixtures, license-checked, committed to repo). Recommended action: bump Pillow to `>=12.2.0` when next test-infra session touches the pin — purely hygienic.

## D-CROSS-CVE-1 / CVE-2025-53644 — Cross-Reference Re-Validation

Cycle-1 leftover `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md` asks the security review team to re-validate CVE-2025-53644 against the currently-pinned `opencv-python==4.11.0.86`.

**Outcome of this scan**: `opencv-python==4.11.0.86` is listed in the pip-audit output with `"vulns": []` — neither PyPI's advisory feed nor OSV.dev has a published advisory tying CVE-2025-53644 to that pin band. The 4.x-line supported branch (per the leftover document) appears to have absorbed the relevant patch in `4.11.0.86`. NFT-SEC-04 (which feeds `cve-jpeg-fixture` to every OpenCV imread/imdecode path under AddressSanitizer) is the executable evidence that confirms this in the test suite.

**Recommendation**: the D-CROSS-CVE-1 leftover entry can remain OPEN because the upstream constraint (gtsam → numpy<2) is unchanged, but the **CVE-2025-53644 exposure window has effectively closed** at the current pin. Update the leftover entry's "CVE exposure window" section to reflect this scan's finding (pip-audit clean against the current pin; NFT-SEC-04 ASan run validates runtime). The pin-replay condition (gtsam numpy-2 wheels) remains the same.

## Out-of-Band Dependencies (Not Audited Here)

| Dep | Why excluded | How audited |
|---|---|---|
| `tensorrt` | Installed via JetPack 6.2 on Jetson Orin Nano Super — not a PyPI distribution | NVIDIA security bulletins + JetPack release notes; tracked in `ci_cd_pipeline.md` § Security as a manual on-deploy SBOM check |
| TRT EP engines (`*.engine`) | Build artifacts, not deps | Engine signing + filename schema validation (helpers/engine_filename_schema.md, sha256_sidecar.md) |
| `gtsam==4.2` (C++ side) | The PyPI wheel embeds a C++ build of GTSAM; CVEs against the C++ library itself are not in PyPI's advisory feed | Monthly osv-scanner against the GTSAM commit pinned in `cmake/dependencies.cmake` per `_docs/02_document/deployment/ci_cd_pipeline.md` § Security |
| Docker base images | `docker/Dockerfile` base + `ardupilot/ardupilot-sitl:plane-stable` + `inavflight/inav-sitl:9.0.0` + `ardupilot/mavproxy:latest` | Trivy on all CI-built images per `ci_cd_pipeline.md` § Security |

## Self-Verification

- [x] All package manifests scanned — `pyproject.toml` is the only one
- [x] Each finding has a CVE ID + advisory alias (GHSA / BIT)
- [x] Upgrade paths identified for every finding (or marked "no fix released" for F6)
- [x] D-CROSS-CVE-1 leftover re-validated against the cycle-1 relaxed pin

## Recommendations

### Immediate (Critical/High)
None — no Critical or High findings in this project's threat model.

### Short-term (Medium)
- **F1**: when the Python-3.12 cap lifts (gtsam numpy-2 unblock), pin `cryptography>=46.0.7` as a coupled bump. Add a one-line note in `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md` so the constraint is replayed in the same session that lifts the opencv pin.

### Long-term (Low / Hardening)
- Bump `pillow` dev-extra pin to `>=12.2.0` (purely hygienic; not exposed).
- Bump `starlette` (via `fastapi` dev-extra pin) to a version ≥ 0.49.1 (purely hygienic; not exposed).
- Bump `idna` indirectly via `requests` / `httpx` next release.
- Watch upstream paramiko for a CVE-2026-44405 fix; bump when published.
- Update D-CROSS-CVE-1 leftover entry to record that CVE-2025-53644 is no longer flagged against the current 4.11.0.86 pin (per this scan).
