diff --git a/docs/maintainers/security-findings-triage-2026-03-15.md b/docs/maintainers/security-findings-triage-2026-03-15.md index c6dd13c6..a78ad8a3 100644 --- a/docs/maintainers/security-findings-triage-2026-03-15.md +++ b/docs/maintainers/security-findings-triage-2026-03-15.md @@ -1,6 +1,6 @@ # Security Findings Triage (2026-03-15) -Maintainer note: later fixes changed the status of several findings after this baseline snapshot. See [`security-findings-triage-2026-03-29-addendum.md`](security-findings-triage-2026-03-29-addendum.md) before using this file as the current source of truth. +Maintainer note: later fixes changed the status of several findings after this baseline snapshot. Use [`security-findings-triage-2026-03-29-refresh.md`](security-findings-triage-2026-03-29-refresh.md) as the current source of truth, and keep this file as the historical baseline snapshot. - Baseline: `origin/main@226f10c2a62fc182b4e93458bddea2e60f9b0cb9` - Input CSV was treated as triage input only, not as ground truth. diff --git a/docs/maintainers/security-findings-triage-2026-03-29-addendum.md b/docs/maintainers/security-findings-triage-2026-03-29-addendum.md index 9f66aba6..9db450a6 100644 --- a/docs/maintainers/security-findings-triage-2026-03-29-addendum.md +++ b/docs/maintainers/security-findings-triage-2026-03-29-addendum.md @@ -3,6 +3,9 @@ This addendum updates the 2026-03-15 baseline after the follow-up hardening work shipped on `main`. +For the full current-head re-triage, use +[`security-findings-triage-2026-03-29-refresh.md`](security-findings-triage-2026-03-29-refresh.md). + ## Corrected / Updated Findings - Finding `1` / `7` (`tools/scripts/sync_microsoft_skills.py`) diff --git a/docs/maintainers/security-findings-triage-2026-03-29-refresh.md b/docs/maintainers/security-findings-triage-2026-03-29-refresh.md new file mode 100644 index 00000000..34b581c8 --- /dev/null +++ b/docs/maintainers/security-findings-triage-2026-03-29-refresh.md @@ -0,0 +1,84 @@ +# Security Findings Re-Triage (2026-03-29) + +This document is the current-head refresh of the historical +[`security-findings-triage-2026-03-15.md`](security-findings-triage-2026-03-15.md) +baseline. + +- Baseline snapshot: `origin/main@226f10c2a62fc182b4e93458bddea2e60f9b0cb9` +- Current verification target: `main@d63d99381b8f613f99c8cb7b758e7879b401f8a0` +- The 2026-03-15 markdown file and CSV remain useful as historical input, not + as the current source of truth. +- Status meanings are unchanged: + `still present and exploitable`, `still present but low practical risk`, + `obsolete/not reproducible on current HEAD`, `duplicate of another finding`. + +## Summary On Current HEAD + +- still present and exploitable: 0 +- still present but low practical risk: 0 +- obsolete/not reproducible on current HEAD: 26 +- duplicate of another finding: 7 + +## High-Level Outcome + +The 2026-03-15 finding set no longer contains a currently reproduced open +security issue on `main`. + +The biggest shifts since the original baseline are: + +- filesystem/symlink hardening in `setup_web.js`, `install.js`, + `sync_microsoft_skills.py`, `generate_index.py`, `fix_skills_metadata.py`, + and `skill-utils.js` +- removal of shared frontend writes for skill saves/stars +- parser hardening for non-mapping YAML frontmatter +- secure extraction in the Office unpack helpers +- migration of predictable `/tmp` state files into user-owned state + directories +- documentation hardening for risky command guidance + +## Detailed Findings + +| # | Current Status | Current HEAD Rationale | Evidence | +|---|---|---|---| +| 1 | obsolete/not reproducible on current HEAD | `sync_microsoft_skills.py` now sanitizes flat names and constrains delete/copy targets to safe in-repo paths. | `tools/scripts/sync_microsoft_skills.py`, `tools/scripts/tests/test_sync_microsoft_skills_security.py` | +| 2 | obsolete/not reproducible on current HEAD | `SkillDetail.tsx` still renders markdown without `rehype-raw`; the reported stored-XSS path does not reproduce. | `apps/web-app/src/pages/SkillDetail.tsx` | +| 3 | obsolete/not reproducible on current HEAD | `setup_web.js` now uses `lstatSync` plus `resolveSafeRealPath()` and skips out-of-root symlinks instead of dereferencing them into public assets. | `tools/scripts/setup_web.js`, `tools/scripts/tests/copy_security.test.js` | +| 4 | obsolete/not reproducible on current HEAD | The Apify skill no longer recommends pipe-to-shell installs or token-on-command-line login; the risky documentation pattern was removed. | `skills/apify-actorization/SKILL.md` | +| 5 | duplicate of another finding | Still the same root cause/fix area as finding `3`. | `tools/scripts/setup_web.js` | +| 6 | duplicate of another finding | Still the same root cause/fix area as finding `3`. | `tools/scripts/setup_web.js` | +| 7 | obsolete/not reproducible on current HEAD | Microsoft sync now rejects unsafe symlink targets and only accepts safe regular files that stay within the cloned source root. | `tools/scripts/sync_microsoft_skills.py`, `tools/scripts/tests/test_sync_microsoft_skills_security.py` | +| 8 | duplicate of another finding | Still the same root cause/fix area as finding `7`. | `tools/scripts/sync_microsoft_skills.py` | +| 9 | obsolete/not reproducible on current HEAD | The tracked `__pycache__` artifacts are absent on current `main`, and repo hygiene tests explicitly fail if they reappear. | `tools/scripts/tests/repo_hygiene_security.test.js` | +| 10 | obsolete/not reproducible on current HEAD | `generate_index.py` now ignores symlinked `SKILL.md` files instead of reading them during index generation. | `tools/scripts/generate_index.py`, `tools/scripts/tests/test_frontmatter_parsing_security.py` | +| 11 | obsolete/not reproducible on current HEAD | The Jetski loader rejects symlinked skill directories/files and refuses any resolved `SKILL.md` outside the configured skills root. | `docs/integrations/jetski-gemini-loader/loader.mjs`, `tools/scripts/tests/jetski_gemini_loader.test.cjs` | +| 12 | obsolete/not reproducible on current HEAD | TLS verification is enabled by default again; insecure behavior now requires an explicit opt-out environment flag. | `skills/junta-leiloeiros/scripts/scraper/base_scraper.py`, `skills/junta-leiloeiros/scripts/web_scraper_fallback.py` | +| 13 | obsolete/not reproducible on current HEAD | The old bundle-category omission path still does not drive shipped bundle output; current bundles come from `build-catalog.js`. | `tools/scripts/build-catalog.js`, `data/bundles.json` | +| 14 | obsolete/not reproducible on current HEAD | The malformed `--- Unknown` frontmatter regression is no longer present in `alpha-vantage`. | `skills/alpha-vantage/SKILL.md`, `tools/scripts/tests/repo_hygiene_security.test.js` | +| 15 | obsolete/not reproducible on current HEAD | `ws_listener.py` now defaults to a user-owned state directory and uses secure file creation instead of predictable shared `/tmp` output files. | `skills/videodb/scripts/ws_listener.py`, `tools/scripts/tests/local_temp_safety.test.js` | +| 16 | obsolete/not reproducible on current HEAD | `refresh-skills-plugin.js` now resolves real paths under the skills root before serving `/skills/*`; the public Pages app also no longer exposes the maintainer sync surface. | `apps/web-app/refresh-skills-plugin.js`, `README.md`, `apps/web-app/README.md` | +| 17 | duplicate of another finding | Still the same root cause/fix area as finding `16`. | `apps/web-app/refresh-skills-plugin.js` | +| 18 | obsolete/not reproducible on current HEAD | `validate_skills.py` now rejects non-mapping YAML frontmatter cleanly instead of crashing downstream validation. | `tools/scripts/validate_skills.py`, `tools/scripts/tests/test_frontmatter_parsing_security.py` | +| 19 | obsolete/not reproducible on current HEAD | `useSkillStars` now stores saves locally in the browser and no longer performs shared frontend writes through the public Supabase client. | `apps/web-app/src/hooks/useSkillStars.ts`, `apps/web-app/src/lib/supabase.ts` | +| 20 | obsolete/not reproducible on current HEAD | `fix_skills_metadata.py` now skips symlinked `SKILL.md` files and non-mapping frontmatter instead of rewriting arbitrary targets. | `tools/scripts/fix_skills_metadata.py` | +| 21 | obsolete/not reproducible on current HEAD | `install.js` now uses `lstatSync` plus `resolveSafeRealPath()` and skips symlinks that resolve outside the cloned repo root. | `tools/bin/install.js`, `tools/scripts/tests/copy_security.test.js` | +| 22 | duplicate of another finding | Still the same root cause/fix area as finding `21`. | `tools/bin/install.js` | +| 23 | duplicate of another finding | Still the same root cause/fix area as finding `1`. | `tools/scripts/sync_microsoft_skills.py` | +| 24 | obsolete/not reproducible on current HEAD | The audio transcription example now uses a quoted heredoc and passes values via environment variables instead of interpolating them into Python source. | `skills/audio-transcriber/examples/basic-transcription.sh` | +| 25 | obsolete/not reproducible on current HEAD | The claimed recursive symlink traversal in catalog discovery still does not reproduce on current code paths. | `tools/lib/skill-utils.js`, `tools/scripts/build-catalog.js` | +| 26 | obsolete/not reproducible on current HEAD | Root `skills_index.json` remains the canonical generated index, so the reported release-script path mismatch does not reproduce as a defect. | `tools/scripts/generate_index.py`, `tools/scripts/update_readme.py`, `tools/scripts/release_workflow.js` | +| 27 | obsolete/not reproducible on current HEAD | `skill-utils.js` now relies on `lstatSync`-based safe directory/file discovery, so normalization does not treat symlinked skill folders as writable local skills. | `tools/lib/skill-utils.js`, `tools/scripts/normalize-frontmatter.js` | +| 28 | obsolete/not reproducible on current HEAD | The `last30days` skill still passes `"$ARGUMENTS"` as a quoted value into a temp file, so the reported direct shell-injection sink does not reproduce from current text. | `skills/last30days/SKILL.md` | +| 29 | duplicate of another finding | Still the same root cause/fix area as finding `18`. | `tools/scripts/generate_index.py`, `tools/scripts/validate_skills.py` | +| 30 | obsolete/not reproducible on current HEAD | The strategic compact hook now stores state under `XDG_STATE_HOME` instead of predictable shared `/tmp` paths. | `skills/cc-skill-strategic-compact/suggest-compact.sh`, `tools/scripts/tests/local_temp_safety.test.js` | +| 31 | obsolete/not reproducible on current HEAD | `sync_recommended_skills.sh` now preserves symlinks with `cp -RP` and avoids the destructive glob-delete pattern called out in the original report. | `tools/scripts/sync_recommended_skills.sh`, `tools/scripts/tests/repo_hygiene_security.test.js` | +| 32 | obsolete/not reproducible on current HEAD | `skills_manager.py` now resolves candidate paths relative to the intended base directory and rejects traversal attempts. | `tools/scripts/skills_manager.py`, `tools/scripts/tests/test_skills_manager_security.py` | +| 33 | obsolete/not reproducible on current HEAD | The Office unpack helpers now validate archive members and reject traversal/symlink-style entries before extraction. | `skills/docx-official/ooxml/scripts/unpack.py`, `skills/pptx-official/ooxml/scripts/unpack.py`, `tools/scripts/tests/test_office_unpack_security.py` | + +## Maintainer Notes + +- Keep the 2026-03-15 markdown file and CSV as the historical baseline record. +- Keep the 2026-03-29 addendum as the intermediate transition note. +- Use this refresh when answering “what is still open right now?” for the + original 2026-03-15 finding set. +- If new findings are discovered later, start a fresh triage cycle rather than + mutating the historical baseline counts again. diff --git a/walkthrough.md b/walkthrough.md index 901dd6a3..24055f26 100644 --- a/walkthrough.md +++ b/walkthrough.md @@ -1,5 +1,19 @@ # Maintenance Walkthrough - 2026-03-29 +- Re-triaged the full 2026-03-15 security finding set against current `main` and wrote a fresh current-head report in `docs/maintainers/security-findings-triage-2026-03-29-refresh.md`. +- Kept the old `2026-03-15` markdown/CSV as historical baseline input, preserved the smaller `2026-03-29` addendum as a transition note, and pointed both docs at the new refresh as the current source of truth. +- The refreshed triage currently lands at: + - `0` findings still present and exploitable + - `0` findings still present but low practical risk + - `26` obsolete/not reproducible on current HEAD + - `7` duplicates +- The refresh folds in the hardening shipped today and earlier in the session: + - symlink/path safety in maintainer/install/web copy flows + - frontmatter parser robustness + - removal of shared frontend star writes + - secure Office unpack behavior + - migration away from predictable `/tmp` state files + - Fixed the remaining production/documentation drift introduced by the web-app and CI hardening work: - clarified that the hosted GitHub Pages app runs in static public-catalog mode - documented that `Sync Skills` is development-only unless explicitly enabled in local maintainer runs