[AZ-243] Record security audit

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-07 03:40:36 +03:00
parent a8e7199f30
commit ee6606a9c2
6 changed files with 262 additions and 2 deletions
+34
View File
@@ -0,0 +1,34 @@
# Dependency Vulnerability Scan
**Date**: 2026-05-07
**Tool**: `pip-audit 2.10.0`
**Manifest**: `pyproject.toml`
**Result**: PASS
## Scope
The scan covered the Python dependencies declared in `pyproject.toml`, including the `dev` optional dependency group:
- `pydantic==2.13.3`
- `black>=24.0`
- `pytest>=8.0`
- `ruff>=0.5`
## Findings
No known vulnerabilities were reported.
## Audit Output Summary
`pip-audit` resolved and checked the project dependency set and returned:
```text
No known vulnerabilities found
```
Resolved packages with no advisories included `pydantic`, `pydantic-core`, `black`, `pytest`, and `ruff`.
## Notes
- `pip-audit` and its own transitive packages were installed as an audit tool in the local Python environment.
- The repository does not currently include a locked production dependency file, so the audit used the version constraints from `pyproject.toml`.
@@ -0,0 +1,49 @@
# Infrastructure Security Review
**Date**: 2026-05-07
**Scope**: Dockerfiles, compose files, environment templates, GitHub Actions
**Result**: PASS_WITH_WARNINGS
## Reviewed Artifacts
- `deployment/docker/Dockerfile.runtime`
- `deployment/docker/Dockerfile.replay`
- `docker-compose.yml`
- `docker-compose.test.yml`
- `.github/workflows/ci.yml`
- `.env.example`
- `config/development/runtime.env`
- `config/ci/runtime.env`
- `config/jetson/runtime.env`
## Findings
| ID | Severity | Category | Location | Title |
|----|----------|----------|----------|-------|
| I1 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Default Postgres password and exposed host port need stronger dev/prod separation |
| I2 | Low | CI/CD Hardening | `.github/workflows/ci.yml` | CI lacks dependency audit / secret scan / SAST gates |
## Finding Details
### I1: Default Postgres password and exposed host port need stronger dev/prod separation
`docker-compose.yml` uses `POSTGRES_PASSWORD=gpsd`, publishes `5432:5432`, and points runtime at `.env.example`, which embeds the same example credentials in `GPSD_DATABASE_URL`.
**Impact**: Safe enough for local development if never deployed, but risky if copied into staging, Jetson, or field environments.
**Remediation**: Move credentials into an ignored local `.env`, document `docker-compose.yml` as development-only, bind local Postgres to loopback, and require production/Jetson credentials from a secret manager or deployment-time secret source.
### I2: CI lacks dependency audit / secret scan / SAST gates
`.github/workflows/ci.yml` runs format, lint, unit tests, and compose config validation, but it does not run dependency audit, secret scanning, or SAST.
**Impact**: Vulnerable dependencies or accidentally committed secrets may be caught only during manual audits.
**Remediation**: Add `pip-audit` for Python dependencies, a secret scanner such as Gitleaks/TruffleHog, and a lightweight SAST pass such as Semgrep or Ruff security rules when the project adopts them.
## Positive Controls
- Runtime and replay Dockerfiles create and run as a non-root `gpsd` user.
- Runtime image copies only project source and `pyproject.toml`/`README.md`, not `.env` or fixture payloads.
- `docker-compose.test.yml` keeps replay/SITL/cache stubs on isolated compose networks and exposes no host ports.
- `config/jetson/runtime.env` contains paths and mode labels only; it does not include embedded passwords or signing keys.
+26
View File
@@ -0,0 +1,26 @@
# OWASP Top 10 Review
**Date**: 2026-05-07
**Reference**: OWASP Top 10:2021, current official Top 10 referenced from <https://owasp.org/www-project-top-ten/>
**Result**: PASS_WITH_WARNINGS
## Assessment
| OWASP Category | Status | Findings / Notes |
|----------------|--------|------------------|
| A01: Broken Access Control | PASS | No web/API authorization surface is implemented in the current runtime code. MAVLink source/system ID and cache trust boundaries are represented in architecture/tests. |
| A02: Cryptographic Failures | PASS_WITH_WARNINGS | No weak crypto or secret leakage found in source. Cache signature checks compare trusted signature hashes, but production key handling remains a deployment concern. |
| A03: Injection | PASS | No SQL construction, shell execution, dynamic code execution, or template rendering paths were found in source. |
| A04: Insecure Design | PASS_WITH_WARNINGS | `S1` is a resource-exhaustion design gap for local VPR descriptor package loading. |
| A05: Security Misconfiguration | PASS_WITH_WARNINGS | `S2` covers default development database credentials and broad host port exposure in `docker-compose.yml`. |
| A06: Vulnerable and Outdated Components | PASS | `pip-audit` reported no known vulnerabilities for the project dependency set. |
| A07: Identification and Authentication Failures | NOT_APPLICABLE | No user/session authentication surface is implemented in this package. |
| A08: Software and Data Integrity Failures | PASS_WITH_WARNINGS | Cache metadata validation is implemented, but CI currently validates tests/compose only; dependency audit and secret/SAST scanning are not yet CI gates. |
| A09: Security Logging and Monitoring Failures | PASS | Architecture and tests require FDR/QGC visibility for cache rejection, spoofing, blackout, and health events. |
| A10: Server-Side Request Forgery | NOT_APPLICABLE | No HTTP client, URL-fetching, or server-side request surface was found in runtime source. |
## OWASP Notes
- The current package is primarily an onboard runtime and replay harness, not a web application. Several OWASP categories are therefore assessed through local trust boundaries: cache package integrity, MAVLink source filtering, runtime configuration, and generated-tile promotion.
- The strongest security controls already represented in code/docs are no in-flight satellite-provider calls, cache manifest/hash checks, spoofed/unauthorized MAVLink rejection tests, and FDR-visible security events.
- Remaining warnings are hardening items rather than exploitable remote vulnerabilities in the current code shape.
+106
View File
@@ -0,0 +1,106 @@
# Security Audit Report
**Date**: 2026-05-07
**Scope**: GPS-denied onboard runtime and replay infrastructure
**Verdict**: PASS_WITH_WARNINGS
## Summary
| Severity | Count |
|----------|-------|
| Critical | 0 |
| High | 0 |
| Medium | 2 |
| Low | 1 |
No Critical or High issues were found. The audit can proceed through the autodev gate, with hardening work recommended before production deployment.
## OWASP Top 10 Assessment
| Category | Status | Findings |
|----------|--------|----------|
| A01: Broken Access Control | PASS | — |
| A02: Cryptographic Failures | PASS_WITH_WARNINGS | Deployment key handling remains a release concern |
| A03: Injection | PASS | — |
| A04: Insecure Design | PASS_WITH_WARNINGS | S1 |
| A05: Security Misconfiguration | PASS_WITH_WARNINGS | S2 / I1 |
| A06: Vulnerable and Outdated Components | PASS | — |
| A07: Identification and Authentication Failures | NOT_APPLICABLE | No auth/session surface in current package |
| A08: Software and Data Integrity Failures | PASS_WITH_WARNINGS | I2 |
| A09: Security Logging and Monitoring Failures | PASS | — |
| A10: Server-Side Request Forgery | NOT_APPLICABLE | No URL-fetching runtime surface |
## Findings
| # | Severity | Category | Location | Title |
|---|----------|----------|----------|-------|
| 1 | Medium | Resource / Input Validation | `src/satellite_service/types.py:67` | VPR index JSON is read fully without size limits |
| 2 | Medium | Security Misconfiguration | `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5` | Default DB credentials and exposed port need dev/prod separation |
| 3 | Low | CI/CD Hardening | `.github/workflows/ci.yml` | CI lacks dependency audit / secret scan / SAST gates |
## Finding Details
### F1: VPR index JSON is read fully without size limits
**Severity**: Medium
**Category**: Resource / Input Validation
**Location**: `src/satellite_service/types.py:67`
`LocalVprIndexPackage.from_json_file()` reads an entire local descriptor package into memory before validation. Descriptor packages are part of the local cache trust boundary and can become large.
**Impact**: A malformed or unexpectedly large package could exhaust memory or stall startup/readiness on Jetson.
**Remediation**: Add a maximum file-size check before reading, cap descriptor record count and descriptor length, and require callers to load only manifest-validated package paths.
### F2: Default DB credentials and exposed port need dev/prod separation
**Severity**: Medium
**Category**: Security Misconfiguration
**Location**: `docker-compose.yml:7`, `docker-compose.yml:9`, `.env.example:5`
The default compose file uses `POSTGRES_PASSWORD=gpsd`, publishes Postgres on `5432:5432`, and the example database URL embeds `gpsd:gpsd`.
**Impact**: Safe enough as a local fixture convention, but risky if reused in staging, Jetson, or field deployment.
**Remediation**: Move credentials to ignored local `.env` files, document the default compose as development-only, bind Postgres to loopback for local runs, and require secret-manager sourced credentials for production/Jetson deploys.
### F3: CI lacks dependency audit / secret scan / SAST gates
**Severity**: Low
**Category**: CI/CD Hardening
**Location**: `.github/workflows/ci.yml`
CI runs format, lint, unit tests, and compose config validation, but not dependency audit, secret scanning, or SAST.
**Impact**: Vulnerable dependencies or accidentally committed secrets may be caught only during manual audits.
**Remediation**: Add `pip-audit`, a secret scanner such as Gitleaks/TruffleHog, and a lightweight SAST pass such as Semgrep or Ruff security rules.
## Dependency Vulnerabilities
| Package | CVE / Advisory | Severity | Fix Version |
|---------|----------------|----------|-------------|
| None | — | — | — |
## Positive Controls
- `pip-audit` reported no known vulnerabilities for the declared Python dependency set.
- No SQL construction, shell execution, dynamic code execution, Pickle/marshal use, weak crypto, hardcoded production secrets, or HTTP URL-fetching runtime surface was found in source.
- Runtime and replay Dockerfiles run as non-root `gpsd`.
- Cache manifest/hash validation, no in-flight satellite-provider access, MAVLink spoofing/source rejection, and FDR-visible security events are represented in code, docs, and tests.
## Recommendations
### Immediate
- None required for Critical/High severity because no Critical/High findings were found.
### Short-Term
- Add size/count limits to VPR descriptor package loading.
- Split local-development database credentials from production/Jetson deploy configuration and restrict local Postgres host binding.
### Long-Term
- Add dependency audit, secret scanning, and SAST to CI.
- Re-run security audit after the deploy step creates final production deployment artifacts.
+45
View File
@@ -0,0 +1,45 @@
# 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.
+2 -2
View File
@@ -2,8 +2,8 @@
## Current Step
flow: greenfield
step: 14
name: Security Audit
step: 15
name: Performance Test
status: not_started
tracker: jira
sub_step: