# Static Analysis **Date**: 2026-05-07 **Scope**: Python source, tests, replay harness, tools, compose/config files **Result**: PASS_WITH_WARNINGS ## Findings | ID | Severity | Category | Location | Title | |----|----------|----------|----------|-------| | S1 | Medium | Resource / Input Validation | `src/satellite_service/types.py:67` | VPR index JSON is read fully without size limits | | S2 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Development database credentials and exposed port are easy to reuse outside dev | ## Finding Details ### S1: VPR index JSON is read fully without size limits **Location**: `src/satellite_service/types.py:67` `LocalVprIndexPackage.from_json_file()` reads the entire configured descriptor package into memory with `Path(package_path).read_text()` and then parses it with `json.loads`. The model validates record shape, but there is no file-size limit, descriptor-count limit, or explicit package path trust check at this boundary. **Impact**: A malformed or unexpectedly large local descriptor package could exhaust memory or stall startup/readiness on a constrained Jetson target. **Remediation**: Add a maximum package size check before reading, cap `records` and descriptor lengths in the Pydantic model, and ensure callers pass only cache-package paths that have already passed manifest/signature validation. ### S2: Development database credentials and exposed port are easy to reuse outside dev **Locations**: - `docker-compose.yml:7` - `docker-compose.yml:9` - `.env.example:5` `docker-compose.yml` sets `POSTGRES_PASSWORD=gpsd` and exposes Postgres on `5432:5432`. `.env.example` also embeds `gpsd:gpsd` in `GPSD_DATABASE_URL`. These are acceptable for local fixture use only if they are clearly kept out of production, but the default compose file name makes accidental reuse plausible. **Impact**: If this compose file is copied into a staging or field environment, the database would run with known credentials and an exposed host port. **Remediation**: Move the default password to an ignored local `.env`, rename or label the compose file as development-only, bind Postgres to `127.0.0.1` where host exposure is required, and add a production compose/deploy template that requires secret-manager sourced credentials. ## Negative Checks - No SQL string construction or database `execute()` calls were found in source. - No `eval`, `exec`, `os.system`, `shell=True`, Pickle, `marshal`, weak hashes, TLS verification bypass, CORS wildcard, or hardcoded production secret patterns were found in source. - `tools/remove_osd_lines.py` uses `subprocess.run()` with an argument list and no shell; this is not command-injection prone in its current form. - Dockerfiles run as a non-root `gpsd` user.