|
| 1 | +# Sensitive-Data Audit — sprint-2-integration @ 29bbcb7 |
| 2 | + |
| 3 | +**Date:** 2026-04-25 |
| 4 | +**Worktree:** `/home/josh/.openclaw/workspace/rasputin-memory-sprint2` |
| 5 | +**Method:** Inline ripgrep / grep across tracked files (excluding `.git/`, `benchmarks/results/*.json`) |
| 6 | +**Status:** Surfaced for user review. **No automatic redactions applied.** |
| 7 | + |
| 8 | +The user requested findings only; classification (KEEP / SCRUB / REPLACE-WITH-PLACEHOLDER) is to be done by the user before Stage 2 cleanup commits. |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Section 1 — Definitely clean |
| 13 | + |
| 14 | +| Category | Result | |
| 15 | +|---|---| |
| 16 | +| Personal email domains (gmail/protonmail/yandex/yahoo/outlook/hotmail/icloud) | None found | |
| 17 | +| Bare "josh" prose mentions (excluding `/home/josh` paths) | None found | |
| 18 | +| Hard-coded API keys with high-entropy patterns (`sk-…`, `csk-…`, `xai-…`, `gsk_…`, Bearer tokens) | None found | |
| 19 | +| Hard-coded `API_KEY=` / `SECRET=` / `TOKEN=` assignments with real values | None found (only `.env.example` placeholders + `hooks/openclaw-mem/README.md` `your-deepseek-api-key` placeholder) | |
| 20 | +| GPU UUIDs (`GPU-xxxxxxxx-…`) | None found | |
| 21 | +| SSH / TLS private keys (`BEGIN RSA/OPENSSH/EC/DSA PRIVATE`) | None found | |
| 22 | +| Telegram bot tokens / Slack tokens / Discord tokens | None found | |
| 23 | +| `pyproject.toml` author/maintainer identity fields | Not set (no `authors = […]` block) | |
| 24 | +| Git committer identity in tracked files | None found | |
| 25 | +| Geographic operational keywords (Frankfurt, iGaming, VLESS, Reality, Hysteria, Sing-Box, Xray, casino) | None found | |
| 26 | +| `.env.example` | All placeholders, no real values | |
| 27 | +| Public IPs (non-RFC1918) in tracked files | None found | |
| 28 | +| Production collection naming as a pure leak | `second_brain` used as default value across ~30 files. Not a secret per se but worth a decision (see Section 4) | |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +## Section 2 — Findings requiring user decision (KEEP / SCRUB / REPLACE) |
| 33 | + |
| 34 | +### 2.1 GitHub username `jcartu` — **17 occurrences across 9 files** |
| 35 | + |
| 36 | +Used as the canonical repo path. Files: |
| 37 | + |
| 38 | +- `README.md:5` — CI badge |
| 39 | +- `CONTRIBUTING.md:6` — clone URL |
| 40 | +- `docs/SETUP.md:19` — clone URL |
| 41 | +- `docs/GETTING_STARTED.md:21` — clone URL |
| 42 | +- `CHANGELOG.md:270-277` — version compare links (×8) |
| 43 | +- `SECURITY.md:15` — security advisory link |
| 44 | +- `pyproject.toml:23-26` — Homepage / Documentation / Repository / Changelog URLs (×4) |
| 45 | + |
| 46 | +**Note:** This IS the project's actual GitHub URL (where it will be archived). Removing it would break working links. The GH username `jcartu` is also publicly tied to the user's identity ("Joshua Cartu") via existing GitHub profile. |
| 47 | + |
| 48 | +**Decision needed:** |
| 49 | +- KEEP (project is already public on this GH user; archive will be at the same URL) |
| 50 | +- SCRUB (replace with generic `OWNER/REPO` placeholder, breaks all links) |
| 51 | +- REPLACE (move to a fresh GH org/user before archive) |
| 52 | + |
| 53 | +--- |
| 54 | + |
| 55 | +### 2.2 Internal LAN hostnames + private IPs in benchmark scripts and experiment write-ups |
| 56 | + |
| 57 | +| File | Line | Content | |
| 58 | +|---|---|---| |
| 59 | +| `benchmarks/run_ce_ab_test.sh` | 23, 27, 37 | `Arcstrider 192.168.1.41` + `CROSS_ENCODER_URL=http://192.168.1.41:9091/rerank` | |
| 60 | +| `benchmarks/run_phase1.sh` | 17, 24 | `192.168.1.41:9091/rerank`, `Arcstrider 5090 GPU` | |
| 61 | +| `benchmarks/run_phase2.sh` | 10 | `192.168.1.41:9091/rerank` | |
| 62 | +| `docs/HYBRID-BRAIN.md` | 308 | `url = "http://192.168.1.41:9091/rerank"` | |
| 63 | +| `experiments/2026-04-05_embedding_qwen3_vs_nomic.md` | 15 | `Sunbreaker (192.168.1.69, ~200ms/embed over LAN)` | |
| 64 | +| `experiments/2026-04-05_qwen3_4096d.md` | 5, 15 | `Sunbreaker`, `Sunbreaker (192.168.1.69:11434)` | |
| 65 | + |
| 66 | +`192.168.1.x` is RFC1918 — not a public-network leak. But: |
| 67 | + |
| 68 | +- `Arcstrider` and `Sunbreaker` are personal machine names, mildly identifying. |
| 69 | +- The IPs reveal the user runs the inference servers on a home LAN. Low operational risk; some users prefer to scrub. |
| 70 | +- The experiment files are dated diary entries — they document the actual research methodology. |
| 71 | + |
| 72 | +**Decision needed:** |
| 73 | +- KEEP (RFC1918 IPs aren't sensitive; hostnames are colorful but not identifying) |
| 74 | +- SCRUB to placeholders (`<RERANKER_HOST>:9091`, `<EMBED_HOST>:11434`) — preserves intent, drops trivia |
| 75 | +- REPLACE Arcstrider/Sunbreaker → "Host A / Host B" or "GPU server / embedding server" |
| 76 | + |
| 77 | +**Note on `experiments/`:** the user said "do not modify .sisyphus/ docs (they document the journey honestly)." Experiments aren't `.sisyphus/`, so they're in scope. But they have the same diary character. Worth confirming the user wants them touched. |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +### 2.3 `/home/josh/` paths in scripts and one doc |
| 82 | + |
| 83 | +| File | Line | Content | |
| 84 | +|---|---|---| |
| 85 | +| `benchmarks/monitor_progress.py` | 6 | `CP = "/home/josh/.openclaw/workspace/rasputin-memory/benchmarks/results/locomo-leaderboard-checkpoint.json"` | |
| 86 | +| `benchmarks/run_phase1.sh` | 4 | `cd /home/josh/.openclaw/workspace/rasputin-memory` | |
| 87 | +| `benchmarks/run_phase2.sh` | 4 | `cd /home/josh/.openclaw/workspace/rasputin-memory` | |
| 88 | +| `benchmarks/run_ce_ab_test.sh` | 4 | `cd /home/josh/.openclaw/workspace/rasputin-memory` | |
| 89 | +| `docs/BACKLOG.md` | 59-60 | `python3 /home/josh/.openclaw/workspace/rasputin-memory/tools/qwen3_reranker_server.py 9091` and `Observed working directory: /home/josh/.openclaw/workspace/rasputin-memory` | |
| 90 | + |
| 91 | +These are functional in scripts (the scripts assume a specific layout) but leak the username "josh" and the OpenClaw home path. |
| 92 | + |
| 93 | +**Decision needed:** |
| 94 | +- KEEP (scripts work as-is for the original developer; forks will need to adjust; harmless on a public repo) |
| 95 | +- SCRUB to `$HOME/...` or `$REPO_ROOT` substitution (works for forks too) |
| 96 | +- SCRUB only the doc occurrence in `BACKLOG.md` (lowest-effort hide of personal path) |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +### 2.4 `OpenClaw` brand references — **30+ occurrences across docs and hooks** |
| 101 | + |
| 102 | +| File group | Notes | |
| 103 | +|---|---| |
| 104 | +| `docs/OPENCLAW-INTEGRATION.md` | Full integration doc (~285 lines) | |
| 105 | +| `docs/AGENT-INTEGRATION.md:59-63` | Cross-references to OpenClaw | |
| 106 | +| `docs/INTEGRATIONS.md:34-43` | OpenClaw section | |
| 107 | +| `docs/GETTING_STARTED.md:114` | Mention | |
| 108 | +| `docs/CONFIGURATION.md:116` | Port allocation note | |
| 109 | +| `hooks/openclaw-mem/` | Whole hook directory + README | |
| 110 | + |
| 111 | +OpenClaw is the user's personal agent framework / project name. References to it are functional documentation. It's a public-ish concept (referenced as `https://github.com/openclaw` in `hooks/openclaw-mem/README.md`). |
| 112 | + |
| 113 | +**Decision needed:** |
| 114 | +- KEEP (functional integration; OpenClaw is a thing the public-repo user cares about) |
| 115 | +- SCRUB (rewrite as "your agent framework" — heavy edit, breaks specificity) |
| 116 | +- KEEP but add a top-of-doc note that OpenClaw is a separate user project |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +### 2.5 GitHub usernames in `hooks/openclaw-mem/` |
| 121 | + |
| 122 | +| File | Line | Content | |
| 123 | +|---|---|---| |
| 124 | +| `docs/OPENCLAW-INTEGRATION.md` | 38 | `git clone https://github.com/phenomenoner/openclaw-mem` | |
| 125 | +| `hooks/openclaw-mem/README.md` | 22 | `git clone https://github.com/wenyupapa-sys/openclaw-mem.git ~/.openclaw/hooks/openclaw-mem` | |
| 126 | + |
| 127 | +Two different GH usernames (`phenomenoner`, `wenyupapa-sys`) referenced for the same repo. Inconsistent — suggests stale / pseudonymous content. |
| 128 | + |
| 129 | +**Decision needed:** |
| 130 | +- KEEP both (preserves existing doc as-is) |
| 131 | +- PICK ONE (canonicalize to whichever URL actually resolves) |
| 132 | +- SCRUB (replace with placeholder owner) |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +### 2.6 `security@rasputin.to` email in `SECURITY.md` |
| 137 | + |
| 138 | +`SECURITY.md:15` — vulnerability disclosure email. |
| 139 | + |
| 140 | +The `rasputin.to` domain may or may not be registered/active. If it's a placeholder, real reporters will bounce. If it IS registered, it's a working contact channel. |
| 141 | + |
| 142 | +**Decision needed:** |
| 143 | +- KEEP (assume domain is set up) |
| 144 | +- VERIFY domain status before archive |
| 145 | +- REPLACE with the GH security advisory link only (drop email line) |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +### 2.7 Production collection name `second_brain` |
| 150 | + |
| 151 | +Used as the default `QDRANT_COLLECTION` value across ~30 files (tools, tests, docs, config, scripts). |
| 152 | + |
| 153 | +This is the user's actual production memory collection name. It's not a secret (Qdrant collection names aren't auth-relevant), and the test suite asserts on this exact string in 5+ tests. Changing it is a breaking change for anyone forking who tries to point at an existing instance. |
| 154 | + |
| 155 | +**Decision needed:** |
| 156 | +- KEEP (functional default; not a secret) |
| 157 | +- RENAME to `rasputin_memory` (more neutral, matches project name; touches ~30 files including tests) |
| 158 | +- KEEP in code, mention "default value is the original developer's collection name; override via `QDRANT_COLLECTION` env var" in README |
| 159 | + |
| 160 | +--- |
| 161 | + |
| 162 | +### 2.8 Medical examples in fact-extraction prompts |
| 163 | + |
| 164 | +| File | Line | Content (excerpt) | |
| 165 | +|---|---|---| |
| 166 | +| `tools/fact_extractor.py` | 217 | `- Health information: specific medications, dosages, conditions, doctors, dates` (instruction text in extractor prompt) | |
| 167 | +| `tools/fact_extractor.py` | 337 | `[{{"fact": "The user increased their medication dosage from 5mg to 7.5mg on March 3"}}, …]` (few-shot example) | |
| 168 | +| `tools/brain/amac.py` | 28 | `"The user's family member had a medical procedure at a major hospital." -> 10,9,10` (A-MAC quality-scoring example) | |
| 169 | + |
| 170 | +These are example sentences in prompt templates. They're synthetic prompt-engineering examples, not real user data. Functional purpose is to teach the LLM what "high-importance personal facts" look like. |
| 171 | + |
| 172 | +**Decision needed:** |
| 173 | +- KEEP (synthetic prompt examples; demonstrate fact-extraction behavior) |
| 174 | +- REPLACE with non-medical equivalents (work, travel, finance) — preserves intent without medical-domain specificity |
| 175 | +- KEEP one, SCRUB others |
| 176 | + |
| 177 | +--- |
| 178 | + |
| 179 | +### 2.9 Reference URL containing the word "affiliate" (per user's audit checklist) |
| 180 | + |
| 181 | +Single hit: |
| 182 | + |
| 183 | +- `docs/OPENCLAW-INTEGRATION.md:255` — `curl -s "http://localhost:7777/search?q=What+did+we+decide+about+the+product+affiliate+deal%3F&limit=5"` |
| 184 | + |
| 185 | +Used as an example query string demonstrating the search API. The word "affiliate" here is generic ("affiliate deal" as a sample business question). No specific affiliate program named. |
| 186 | + |
| 187 | +**Decision needed:** |
| 188 | +- KEEP (generic business example, no operational link) |
| 189 | +- REPLACE with neutral example (`What+did+we+decide+about+the+product+launch%3F`) |
| 190 | + |
| 191 | +--- |
| 192 | + |
| 193 | +## Section 3 — Items the user explicitly listed but were not found |
| 194 | + |
| 195 | +The user's audit checklist included these patterns. Confirming all clean: |
| 196 | + |
| 197 | +- `joshua` (full name) — no hits |
| 198 | +- `cartu` — only in `jcartu` GH username (Section 2.1) |
| 199 | +- `iGaming`, `VLESS`, `Reality`, `Hysteria`, `Sing-Box`, `Xray` — no hits |
| 200 | +- `Frankfurt` — no hits |
| 201 | +- `honcho`, `cartu-proxy`, `wikiluck`, `casino-dashboard`, `enrich-daemon`, `rippers` — no hits except `Honcho` mentioned in `CHANGELOG.md:27-31` as a removed integration ("dead code — service decommissioned"). This is a *negative* mention in the changelog explicitly documenting Honcho was removed. Decision: probably KEEP (changelog entries are historically honest; documenting that something was removed is good practice). |
| 202 | + |
| 203 | +--- |
| 204 | + |
| 205 | +## Section 4 — Other observations worth flagging |
| 206 | + |
| 207 | +### 4.1 `.github/workflows/publish.yml` |
| 208 | +Uses `${{ github.actor }}` for image publishing — this is the GH Actions runtime variable, not a hardcoded user. ✅ Clean. |
| 209 | + |
| 210 | +### 4.2 `.github/dependabot.yml` |
| 211 | +Standard config, no identity. ✅ Clean. |
| 212 | + |
| 213 | +### 4.3 `pyproject.toml` package metadata |
| 214 | +Notably has NO `authors = […]` block. Adding one for the public archive (e.g., `authors = [{name = "RASPUTIN Contributors"}]`) is optional. ✅ Currently neutral. |
| 215 | + |
| 216 | +### 4.4 Hooks subproject (`hooks/openclaw-mem/`) |
| 217 | +Self-contained; has its own README. The user may want to: |
| 218 | +- KEEP it (functional integration, useful for OpenClaw users) |
| 219 | +- DROP it (separates the public archive from the personal-framework integration) |
| 220 | + |
| 221 | +The hook readme references separate GH repos (`phenomenoner/openclaw-mem`, `wenyupapa-sys/openclaw-mem`, `openclaw` org) — see Section 2.5. |
| 222 | + |
| 223 | +--- |
| 224 | + |
| 225 | +## Section 5 — Recommended scope for Stage 2 cleanup commit (subject to user decision) |
| 226 | + |
| 227 | +Based on findings, the **most defensible minimum scrub** for a public archive is: |
| 228 | + |
| 229 | +1. **Replace `192.168.1.x` IPs in benchmark scripts and `docs/HYBRID-BRAIN.md`** with `${RERANKER_HOST}` / `${EMBED_HOST}` env-var placeholders (keeps scripts functional, removes home-LAN trivia). |
| 230 | +2. **Replace `/home/josh/...` absolute paths in benchmark scripts and `docs/BACKLOG.md`** with `$REPO_ROOT` / relative paths. |
| 231 | +3. **Verify `security@rasputin.to`** resolves OR drop the email line in `SECURITY.md`, leaving the GH security advisory link. |
| 232 | +4. **Leave `jcartu`** — the archive lives at that GH path. |
| 233 | +5. **Leave `OpenClaw` references** — functional integration docs. |
| 234 | +6. **Leave `Arcstrider` / `Sunbreaker` hostnames** unless the user wants them genericized. |
| 235 | +7. **Leave `second_brain` collection name** — functional default, not a secret. |
| 236 | +8. **Leave medical prompt examples** — synthetic teaching examples, no real user data. |
| 237 | + |
| 238 | +Maximum scrub (additional): |
| 239 | +- Replace `Arcstrider` / `Sunbreaker` with neutral host names in experiments + scripts. |
| 240 | +- Replace medical examples with neutral domain examples. |
| 241 | +- Drop or rewrite `experiments/2026-04-05_*.md` (diary character). |
| 242 | +- Add a generic `authors` block to `pyproject.toml`. |
| 243 | + |
| 244 | +--- |
| 245 | + |
| 246 | +## Section 6 — User decisions required before Stage 2 |
| 247 | + |
| 248 | +For each numbered subsection in Section 2, the user should mark each finding: |
| 249 | + |
| 250 | +- **K** = Keep as-is |
| 251 | +- **S** = Scrub (delete entirely) |
| 252 | +- **R** = Replace with placeholder |
| 253 | +- **F** = Flag for further investigation |
| 254 | + |
| 255 | +A simple decision matrix: |
| 256 | + |
| 257 | +``` |
| 258 | +2.1 jcartu username [ K / S / R / F ] |
| 259 | +2.2 Arcstrider/Sunbreaker + LAN IPs [ K / S / R / F ] |
| 260 | +2.3 /home/josh paths [ K / S / R / F ] |
| 261 | +2.4 OpenClaw brand references [ K / S / R / F ] |
| 262 | +2.5 phenomenoner/wenyupapa-sys URLs [ K / S / R / F ] |
| 263 | +2.6 security@rasputin.to [ K / S / R / F ] |
| 264 | +2.7 second_brain collection name [ K / S / R / F ] |
| 265 | +2.8 Medical prompt examples [ K / S / R / F ] |
| 266 | +2.9 "affiliate" example query [ K / S / R / F ] |
| 267 | +``` |
| 268 | + |
| 269 | +Once the user provides decisions, Stage 2 will execute the scrub commit with the corresponding edits. |
0 commit comments