|
| 1 | +# Security Scan Report |
| 2 | + |
| 3 | +**Generated:** 2026-06-01 |
| 4 | +**Scan Type:** Weekly Scheduled |
| 5 | +**Repository:** EffortlessMetrics/tokmd-swarm |
| 6 | +**Severity Threshold:** medium |
| 7 | +**Scope:** Last 7 days of commits (1 commit: initial import, plus standing defenses audit) |
| 8 | + |
| 9 | +## Executive Summary |
| 10 | + |
| 11 | +| Severity | Count | Auto-fixed | Manual Required | |
| 12 | +|----------|-------|------------|-----------------| |
| 13 | +| CRITICAL | 0 | 0 | 0 | |
| 14 | +| HIGH | 0 | 0 | 0 | |
| 15 | +| MEDIUM | 0 | 0 | 0 | |
| 16 | +| LOW | 0 | 0 | 0 | |
| 17 | + |
| 18 | +**Total Findings:** 0 |
| 19 | +**Auto-fixed:** 0 |
| 20 | +**Manual Review Required:** 0 |
| 21 | + |
| 22 | +**Summary:** No vulnerabilities at or above the `medium` severity threshold were |
| 23 | +identified during this scan. The codebase demonstrates a security-first design |
| 24 | +with multiple defense-in-depth measures already in place (see |
| 25 | +`.factory/threat-model/threat-model.md` for the full STRIDE analysis). One |
| 26 | +transitive `RUSTSEC-2020-0163` advisory (transitive `term_size` via `tokei`) |
| 27 | +is already documented in `deny.toml` and is out of scope per `SECURITY.md`. |
| 28 | + |
| 29 | +## Critical Findings |
| 30 | + |
| 31 | +*None.* |
| 32 | + |
| 33 | +## High Findings |
| 34 | + |
| 35 | +*None.* |
| 36 | + |
| 37 | +## Medium Findings |
| 38 | + |
| 39 | +*None.* |
| 40 | + |
| 41 | +## Low Findings |
| 42 | + |
| 43 | +*None.* |
| 44 | + |
| 45 | +## Observations (Below Threshold — Not Reported As Findings) |
| 46 | + |
| 47 | +These items were considered during the scan but do not meet the `medium` severity |
| 48 | +threshold. They are recorded here for traceability and the next scheduled scan. |
| 49 | + |
| 50 | +### OBS-001: FFI JSON payload size not bounded |
| 51 | + |
| 52 | +| Attribute | Value | |
| 53 | +|-----------|-------| |
| 54 | +| **Severity** | LOW (informational) | |
| 55 | +| **STRIDE Category** | Denial of Service | |
| 56 | +| **File** | `crates/tokmd-core/src/ffi/mod.rs` | |
| 57 | +| **Status** | Not patched — design choice | |
| 58 | + |
| 59 | +**Description:** |
| 60 | +The `run_json(mode, args_json)` FFI entrypoint accepts a JSON string of |
| 61 | +arbitrary size. While individual in-memory `inputs[].path` is bounded to |
| 62 | +4096 bytes (`MAX_IN_MEMORY_INPUT_PATH_BYTES`), the outer JSON envelope is |
| 63 | +not. A caller (Python / Node binding) could pass a multi-megabyte JSON |
| 64 | +string. |
| 65 | + |
| 66 | +**Why not a finding:** |
| 67 | +- Caller controls input. The library runs in the caller's process. |
| 68 | +- `serde_json::from_str` allocates predictably; no algorithmic blowup. |
| 69 | +- No `medium` reachability: requires the caller to opt in. |
| 70 | +- Out of scope per `SECURITY.md` ("Issues in third-party dependencies" |
| 71 | + and "Theoretical attacks without a realistic exploitation scenario"). |
| 72 | + |
| 73 | +**Recommended fix (optional, future):** |
| 74 | +Add a soft cap on `args_json.len()` (e.g. 8 MiB) returning a typed |
| 75 | +`TokmdError::invalid_field("args", "JSON args exceed 8 MiB cap")` from |
| 76 | +`run_json_inner`. Document the limit in the Python and Node API docs. |
| 77 | + |
| 78 | +### OBS-002: Transitive `RUSTSEC-2020-0163` advisory |
| 79 | + |
| 80 | +| Attribute | Value | |
| 81 | +|-----------|-------| |
| 82 | +| **Severity** | LOW (transitive) | |
| 83 | +| **STRIDE Category** | Elevation of Privilege | |
| 84 | +| **File** | `Cargo.lock` (transitive `term_size` via `tokei`) | |
| 85 | +| **Status** | Documented in `deny.toml` | |
| 86 | + |
| 87 | +**Description:** |
| 88 | +`term_size` is a transitive dependency of `tokei` and has an unmaintained |
| 89 | +advisory (`RUSTSEC-2020-0163`). |
| 90 | + |
| 91 | +**Why not a finding:** |
| 92 | +- Already documented in `deny.toml` with rationale: "transitive via tokei; |
| 93 | + revisit when upstream removes it". |
| 94 | +- Out of scope per `SECURITY.md` ("Bugs in third-party dependencies — report |
| 95 | + these upstream"). |
| 96 | + |
| 97 | +**Recommended action:** |
| 98 | +Track upstream `tokei` for a `term_size` removal. No action required from |
| 99 | +this repo. |
| 100 | + |
| 101 | +### OBS-003: GitHub Actions SHA-pinning is not automated |
| 102 | + |
| 103 | +| Attribute | Value | |
| 104 | +|-----------|-------| |
| 105 | +| **Severity** | LOW (informational) | |
| 106 | +| **STRIDE Category** | Spoofing / Tampering | |
| 107 | +| **File** | `.github/workflows/*.yml` | |
| 108 | +| **Status** | Not patched — manual process | |
| 109 | + |
| 110 | +**Description:** |
| 111 | +All GitHub Actions in this repo are pinned by SHA with a comment naming the |
| 112 | +upstream version (e.g. `actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2`). |
| 113 | +There is no automated tooling (e.g., Dependabot for GitHub Actions) verifying |
| 114 | +the SHA → tag mapping is consistent and unrotated. |
| 115 | + |
| 116 | +**Why not a finding:** |
| 117 | +- SHA-pinning is the current best practice. |
| 118 | +- Dependabot is a quality concern, not a vulnerability. |
| 119 | + |
| 120 | +**Recommended action (optional):** |
| 121 | +Consider enabling Dependabot for GitHub Actions (`.github/dependabot.yml` |
| 122 | +already exists for cargo) to keep SHAs current. |
| 123 | + |
| 124 | +## Standing Defenses Verified (No Regression) |
| 125 | + |
| 126 | +The following defenses were re-verified during this scan. All remain intact. |
| 127 | + |
| 128 | +| ID | Defense | Location | Verified | |
| 129 | +|----|---------|----------|----------| |
| 130 | +| D-01 | `unsafe_code = "forbid"` workspace lint | `Cargo.toml` | ✓ | |
| 131 | +| D-02 | `unwrap_used`, `expect_used`, `panic`, `unreachable` lints denied | `Cargo.toml` | ✓ | |
| 132 | +| D-03 | Git subprocess env isolation (`GIT_REPO_SHAPING_ENV`) | `crates/tokmd-git/src/command.rs`, `crates/tokmd/src/git_support.rs` | ✓ | |
| 133 | +| D-04 | Git ref validation (`env_base_ref_is_safe` + `--end-of-options`) | `crates/tokmd-git/src/refs.rs` | ✓ | |
| 134 | +| D-05 | Bounded path canonicalization under root | `crates/tokmd-scan/src/path/bounded_path.rs` | ✓ | |
| 135 | +| D-06 | FFI in-memory input path validation | `crates/tokmd-core/src/ffi/inputs.rs` | ✓ | |
| 136 | +| D-07 | Strict JSON parsing with type validation | `crates/tokmd-core/src/ffi/parse.rs` | ✓ | |
| 137 | +| D-08 | Per-family schema versioning | `crates/tokmd-types/src/` | ✓ | |
| 138 | +| D-09 | SHA-pinned GitHub Actions | `.github/workflows/*.yml` | ✓ | |
| 139 | +| D-10 | Branch protection on `main` (CODEOWNERS, 1 approval, CI required) | `.github/settings.yml` | ✓ | |
| 140 | +| D-11 | `cargo-deny` advisory + license allowlist | `deny.toml` | ✓ | |
| 141 | +| D-12 | BLAKE3 redaction with extension allowlist | `crates/tokmd-format/src/redact/mod.rs`, `crates/tokmd-format/src/redact/extensions.rs` | ✓ | |
| 142 | +| D-13 | Content reads bounded by `ContentLimits` | `crates/tokmd-analysis/src/content/mod.rs` | ✓ | |
| 143 | +| D-14 | PyO3 FFI invariants (no panic, GIL release, error translation) | `crates/tokmd-python/src/lib.rs` | ✓ | |
| 144 | +| D-15 | WASM uses `MemFs` (no host fs) | `crates/tokmd-wasm/` | ✓ | |
| 145 | + |
| 146 | +## Appendix |
| 147 | + |
| 148 | +### Threat Model |
| 149 | + |
| 150 | +- **Status:** Newly generated |
| 151 | +- **Location:** `.factory/threat-model/threat-model.md` |
| 152 | +- **Methodology:** STRIDE |
| 153 | +- **Next review:** 2026-09-01 (90-day cadence) or upon architecture change |
| 154 | + |
| 155 | +### Scan Metadata |
| 156 | + |
| 157 | +- **Commits Scanned:** 1 (`00dbbbf549d4b13e0c44bc750cd80e9527bb2306` — "ci(plan): show estimate source in summary") |
| 158 | +- **Files in scope:** 2428 (entire repository — single-commit import) |
| 159 | +- **Scan Duration:** ~3m |
| 160 | +- **Skills Used:** commit-security-scan (manual), vulnerability-validation (manual), security-review (manual), threat-model-generation |
| 161 | +- **Manual Reviewers:** 1 (Droid scheduled security scan) |
| 162 | +- **False Positive Filter:** applied — see Observations above |
| 163 | + |
| 164 | +### Scan Coverage Matrix |
| 165 | + |
| 166 | +| Area | Files reviewed | Findings | |
| 167 | +|------|----------------|----------| |
| 168 | +| CLI argv parsing | `crates/tokmd/src/cli/`, `crates/tokmd/src/commands/*.rs` | 0 | |
| 169 | +| Subprocess invocation | `crates/tokmd-git/`, `crates/tokmd-cockpit/src/supply_chain.rs`, `crates/tokmd/src/git_support.rs` | 0 | |
| 170 | +| Path handling | `crates/tokmd-scan/src/path/`, `crates/tokmd-scan/src/roots.rs`, `crates/tokmd-scan/src/walk/` | 0 | |
| 171 | +| FFI inputs | `crates/tokmd-core/src/ffi/`, `crates/tokmd-python/src/`, `crates/tokmd-node/src/` | 0 | |
| 172 | +| File content reads | `crates/tokmd-analysis/src/content/`, `crates/tokmd-io-port/src/` | 0 | |
| 173 | +| Redaction / hashing | `crates/tokmd-format/src/redact/` | 0 | |
| 174 | +| GitHub workflows | `.github/workflows/*.yml`, `.github/settings.yml`, `action.yml` | 0 | |
| 175 | +| Build / lint | `Cargo.toml`, `deny.toml`, `clippy.toml`, `.cargo/` | 0 | |
| 176 | +| Githooks | `.githooks/pre-commit`, `.githooks/pre-push`, `.claude/hooks/format-rust.sh` | 0 | |
| 177 | + |
| 178 | +### Commit-level Analysis |
| 179 | + |
| 180 | +Only one commit falls within the 7-day window: |
| 181 | + |
| 182 | +``` |
| 183 | +00dbbbf549d4b13e0c44bc750cd80e9527bb2306 |
| 184 | +Author: Steven Zimmerman, CPA <15812269+EffortlessSteven@users.noreply.github.com> |
| 185 | +Date: Mon Jun 1 05:35:46 2026 -0400 |
| 186 | +Subject: ci(plan): show estimate source in summary |
| 187 | +``` |
| 188 | + |
| 189 | +This commit is the initial repository import (`git log --all --oneline` returns |
| 190 | +exactly 1 commit). It contains 2428 files (`.cargo/config.toml`, the workspace |
| 191 | +source tree, all GitHub workflows, agent manifests, etc.). The CI workflow change |
| 192 | +referenced in the subject ("ci(plan): show estimate source in summary") modifies |
| 193 | +`.github/workflows/pr-plan.yml` to surface the `estimate_source` field. |
| 194 | + |
| 195 | +**Review of the CI change:** |
| 196 | +- Touches only `.github/workflows/pr-plan.yml` (CI step summary content). |
| 197 | +- No new secrets, no new permissions, no new third-party action. |
| 198 | +- No shell-out to untrusted input. |
| 199 | +- No change to environment variable handling. |
| 200 | + |
| 201 | +**No security findings in this commit.** |
| 202 | + |
| 203 | +### Patches Generated |
| 204 | + |
| 205 | +No patches were generated this scan (no findings at or above `medium`). |
| 206 | + |
| 207 | +### Next Scan |
| 208 | + |
| 209 | +The next scheduled security scan runs Monday, 2026-06-08 via |
| 210 | +`.github/workflows/droid-security-scan.yml` (cron `0 8 * * 1`). |
| 211 | + |
| 212 | +## References |
| 213 | + |
| 214 | +- [CWE Database](https://cwe.mitre.org/) |
| 215 | +- [STRIDE Threat Model](https://docs.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats) |
| 216 | +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) |
| 217 | +- [Rust Security Advisory Database](https://rustsec.org/) |
| 218 | +- [CII Best Practices](https://www.bestpractices.dev/) |
| 219 | +- Repository security policy: `SECURITY.md` |
| 220 | +- Repository threat model: `.factory/threat-model/threat-model.md` |
0 commit comments