From 17a9be7dc54dd0632ecbc026671102f7b523c423 Mon Sep 17 00:00:00 2001 From: choiyounggi <74581798+choiyounggi@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:54:39 +0900 Subject: [PATCH] knowledge: ingest 4 verified insight(s) --- .dev-loop/INGEST_REPORT.md | 162 +++++++++++++----- INDEX.md | 2 +- log.md | 1 + wiki/debugging/methodology/reproduce-first.md | 6 +- .../worktree-isolated-workers.md | 7 +- .../process-identity-by-path-and-hash.md | 64 +++++++ .../verifying-assumed-security-agents.md | 63 +++++++ wiki/security/index.md | 12 +- 8 files changed, 267 insertions(+), 50 deletions(-) create mode 100644 wiki/security/incident-response/process-identity-by-path-and-hash.md create mode 100644 wiki/security/incident-response/verifying-assumed-security-agents.md diff --git a/.dev-loop/INGEST_REPORT.md b/.dev-loop/INGEST_REPORT.md index 55ccfd1..6b20d0e 100644 --- a/.dev-loop/INGEST_REPORT.md +++ b/.dev-loop/INGEST_REPORT.md @@ -1,53 +1,129 @@ -# Knowledge consolidation — 15 open PRs (#17–#40) → one reconciled state +# Knowledge flush — 4 insight(s) -The 15 open `knowledge/*` PRs (created 2026-08-04 → 2026-08-05, before the -harvest processed-store dedupe fix in #41) contained 123 file-versions of ~75 -unique pages, with the same insight landing at up to 3 different paths across -up to 8 PRs. Per-PR review would re-import those duplicates, so — as with the -#6–#13 consolidation — this branch carries the reconciled end-state and the 15 -PRs are closed in its favor. +Queue contained 5 pending rows across 4 session files; two rows (hashes +`e44b870e42ca9d9a` / `f5bba19794bcdae8`) were English/Korean duplicates of the +same insight harvested in one session, folded into one candidate. Net: 4 unique +insights, all processed. ## Verified best-practice -Every adopted page's sources were carried from its originating PR's flush, where -they were live-verified at flush time; no new URLs were introduced during -consolidation (checked mechanically: every `http(s)` URL in every merged page -appears in a source PR's diff; every added body line in amended pages traces to -a source PR hunk — orphan-line verification). Confidence fields were kept as the -originating flushes set them, except client-side-rate-limiting where the union -of provider-doc citations (Okta, Auth0, GitHub, OpenAI, RFC 6585) supports -`verified` for the load-bearing claims. One subagent's fabricated content (12 -files matching neither main nor any PR, with invented source URLs) was detected -by the same verification and replaced with true PR content. +**1. Gitignored coordinator-state dirs are absent from git worktrees — hand +workers absolute paths.** +Claim: a repo-relative path under a gitignored directory (`.orchestration/`) +resolves in the coordinator's main checkout but silently misses in every +worker's worktree, because `git worktree add` checks out tracked files only. +Verified by local reproduction this session (git, macOS): repo with +`.gitignore: .orchestration/` + populated `.orchestration/status/`; +`git worktree add ../wt1 -b wt1` → `ls ../wt1/.orchestration` = "No such file +or directory", `cat .orchestration/status/run.json` from the worktree cwd +failed, `git ls-files .orchestration` = 0. Consistent with +https://git-scm.com/docs/git-worktree (linked worktrees are separate checkouts +of the branch). **Confidence: verified.** + +**2. Verify a documented EDR claim on the host before reasoning from it.** +Claim: docs asserting "this host runs SentinelOne/EDR" must be checked against +the host (vendor dir + process grep + `systemextensionsctl list` together); +all-empty means "not installed", not "failed to detect". Mechanism verified +against https://www.elastic.co/blog/mac-system-extensions-for-threat-detection-part-3 +and https://github.com/redcanaryco/mac-monitor/wiki/5.-Endpoint-Security-Overview +(post-kext-deprecation, macOS EDRs ship Endpoint Security clients as system +extensions, enumerable via `systemextensionsctl list`); all three commands +re-run this session on this macOS host (Darwin 25.1.0) reproducing the +incident's empty results. Field incident: root XMRig ran 4d8h on a host whose +global CLAUDE.md claimed SentinelOne. **Confidence: verified.** + +**3. Judge a miner-suspect process by executable path + signature, never by +name.** +Claim: malware adopts legitimate daemon names; macOS ships a genuine +`/usr/libexec/sysmond`, so name-based kills hit the Apple daemon or miss the +miner. Verified this session: `ls -l /usr/libexec/sysmond` (root:wheel), +`man -w sysmond` → man8 page, `codesign -vv` → valid / satisfies Designated +Requirement, `codesign -dv` → `Identifier=com.apple.sysmond`, +`Authority=Software Signing`. Technique documented at +https://attack.mitre.org/techniques/T1036/005/ ("giving it the name of a +legitimate, trusted program", fetched and confirmed this session). Field +incident: quarantined `~/.config/sysmond` was XMRig 6.26.0 by its own log +header. **Confidence: verified.** + +**4. For prod-only failures the client swallows, grep the service logs for the +endpoint path before reading more code.** +Claim: when the frontend `.catch()`-swallows errors, a 500 and a no-op are +indistinguishable from the UI; one server-side exception line kills hypothesis +families. Field evidence: chungyak-alimi bookmark bug — backend/proxy/browser +all verified normal, then one `journalctl | grep bookmark` surfaced +PostgreSQL's "no unique or exclusion constraint matching the ON CONFLICT +specification" → deployed DB on an old schema. The PostgreSQL mechanism +(ON CONFLICT arbiter inference raises an error without a matching unique +index) confirmed against https://www.postgresql.org/docs/current/sql-insert.html. +The directive itself is production experience aligned with +https://sre.google/sre-book/effective-troubleshooting/ (already a page source). +**Confidence: field-tested** (marked as such in the added source line). ## Existing-layer check -- Merged-main near-dup scan before consolidation: pairwise Jaccard over - title + "When this applies" across all 141 merged pages → **0 flagged pairs**; - previously merged content carries no duplication. -- Cross-PR dedup during consolidation: 10 duplicate clusters collapsed to one - canonical page each (rate limiting 8→1, call-site enumeration 7→folded into - the canonical merged in #20, stderr/exit-0 diagnostics 4→1, sysroot 2→1, - env-off-switch 2→1, completion predicates 2→1, robots.txt 2→1, - harness-mediated results 2→1, leaked artifacts 2→1, orchestration category - naming unified). Three near-pairs kept distinct after trigger comparison, - with mutual `related:` links (differential setup vs interpretation; expansion - semantics vs off-switch design; import-time tactics vs level choice). -- 24 existing pages received union-merged amendments; additions already present - in main (from #16/#20) were skipped, and all non-canonical `related:` ids - were remapped to canonical page ids (post-merge broken-link scan: 0). +Pages read: infrastructure-agent-orchestration-worktree-isolated-workers, infrastructure-agent-orchestration-shared-run-state, debugging-methodology-reproduce-first, debugging-signals-logs-and-correlation + +Also read: root `INDEX.md`, `wiki/infrastructure/index.md`, +`wiki/security/index.md`, `wiki/debugging/index.md` (routing), and +`skills/wiki-ingest/SKILL.md` + `templates/page.md` + `AGENTS.md` format rules. + +- Insight 1 overlaps `worktree-isolated-workers` (same trigger family, new + failure mode) → **merged** there: +1 edge case, +1 instead-of row, +1 + reproduction source. No conflict: the page's "write produced paths + worktree-relative" directive concerns worker *output*; this case concerns + coordinator-state paths workers must *read*, and reads of absolute main-root + paths pass the guardrail per the page's own table. Related link added + worktree-isolated-workers → shared-run-state (reverse link already existed). +- Insight 4 overlaps `reproduce-first`'s prod-only evidence row → **merged** + there: +1 edge case (silent-swallow), +1 field source. Related links now + bidirectional with `logs-and-correlation` (that page already pointed at + reproduce-first in an edge-case row). +- Insights 2–3: read every security category in `wiki/security/index.md` + (input, api-exposure, authn, authz, secrets, dependencies, data) — all cover + designing trust boundaries in code; none covers live host-compromise triage. + No duplicate, no conflicting directive. → **new pages** (see Routing). + +## Open-PR check + +Listed 25 open `knowledge/*` heads (#47–#91). Same-branch heads fetched +directly; fork PRs (#49, #52, #72, #73, #74, #76, #78, #86, #91) fetched via +`pull//head`. All 25 diffs against `origin/main -- wiki/` were concatenated +and keyword-swept (gitignore, EDR, sentinel, sysmond, xmrig, miner, incident, +systemextensionsctl, swallow, `.catch(`, server/production log, prod-only). + +- Insight 1: #47 and #51 also edit `worktree-isolated-workers.md`, but both add + guardrail read-escalation version behavior — no overlap with the + gitignored-dir-absent-in-worktree case (their hunks inspected in full). + Verdict: **new** (file-level merge conflict possible with #47/#51; content + disjoint — flagged here for the owner's merge ordering). +- Insight 2: EDR/SentinelOne keyword hits were pre-existing removed lines in + #47/#51's `permissions-and-exec-bits` context, unrelated. Verdict: **new**. +- Insight 3: no hit for sysmond/miner/masquerade in any open head. Verdict: + **new**. +- Insight 4: no open head touches `reproduce-first.md` or + `logs-and-correlation.md`; silent-failure hits were unrelated env-var pages. + Verdict: **new**. + +No candidate was folded into an in-flight branch; none dropped as a pending +duplicate. ## Routing decision -- New categories: `infrastructure/agent-orchestration` (5 pages; unified the - competing `orchestration`/`agent-orchestration` names), `databases/data-survey` - (1), `qa/deliverables` (1). All other pages route into existing categories. -- Canonical-path decisions: rate limiting → `backend/common/reliability/` - (sits beside timeouts-and-retries; 6 of 8 variants chose it); stderr - diagnostics → `platforms/processes/` (concern spans beyond shells); leaked - artifacts → `testing/data/artifact-leakage-from-a-suite`; call-site - enumeration → the existing `backend/common/change-impact/` page. -- All 38 new pages listed in their domain indexes (nearest-index rule; backend - routes via its python sub-index for bytecode-cache-staleness); INDEX.md domain - summaries updated for infrastructure/qa/databases. Full-wiki lint: frontmatter, - ids, related-links, index coverage, size, qualifiers, staleness → 0 findings. +- Insight 1 → `infrastructure/agent-orchestration/worktree-isolated-workers` + (merge; harvested domain hint "infrastructure" confirmed). +- Insight 2 → `security/incident-response/verifying-assumed-security-agents` + (**new category** `incident-response`): existing security categories all + govern designing/reviewing trust boundaries in code (input, api-exposure, + authn, authz, secrets, dependencies, data); responding to a live host + compromise fits none of them, and debugging/platforms were rejected + (debugging owns diagnosing code failures; platforms owns cross-OS code + breakage, not threat triage). Domain index + root INDEX.md security row + updated. +- Insight 3 → `security/incident-response/process-identity-by-path-and-hash` + (same new category; the two pages cross-reference via `related:`). +- Insight 4 → `debugging/methodology/reproduce-first` (merge; harvested domain + hint "debugging" confirmed). + +Queue retirement: all 5 rows (4 insights + 1 language duplicate) appended to +`~/.dev-loop/queue/.processed.jsonl` and their session files rewritten/deleted +after PR creation. diff --git a/INDEX.md b/INDEX.md index cb6cd09..7fd3319 100644 --- a/INDEX.md +++ b/INDEX.md @@ -16,7 +16,7 @@ follow the cross-pointers in their index or take the next matching seeded domain | [testing](wiki/testing/index.md) | **seeded** | Writing or structuring automated tests: level choice, cases/assertions, test data, mock decisions, flaky tests (release-process quality → qa) | | [qa](wiki/qa/index.md) | **seeded** | Release-quality process: release gates, regression scoping, bug reports, severity/priority triage, exploratory testing (guarded-path coverage, override matrices), scope-purity gates, sourcing deliverable documents from generated artifacts, automated verification of document deliverables (spec/RFC gates) (writing automated test code → testing) | | [debugging](wiki/debugging/index.md) | **seeded** | Diagnosing a failure — finding what is wrong and why: reproducing, bisection, hypothesis testing, traces/logs, intermittent failures (fixing the diagnosed fault → its owning domain) | -| [security](wiki/security/index.md) | **seeded** | Trust-boundary decisions: input validation, session-vs-token auth choice, per-resource authorization (IDOR), secrets hygiene, dependency trust, PII handling (XSS rendering → frontend; CI secrets → infrastructure; JWT implementation → backend/frontend auth) | +| [security](wiki/security/index.md) | **seeded** | Trust-boundary decisions: input validation, session-vs-token auth choice, per-resource authorization (IDOR), secrets hygiene, dependency trust, PII handling; host-compromise triage / incident response (verifying assumed security agents, identifying masquerading processes) (XSS rendering → frontend; CI secrets → infrastructure; JWT implementation → backend/frontend auth) | | [platforms](wiki/platforms/index.md) | **seeded** | OS-level differences breaking code across macOS/Linux/Windows: shell portability, BSD-vs-GNU CLI, filesystem case/line endings, Unicode normalization in text/file-name matching, commands inspected before execution, background services/cron, invoking prompt-capable CLIs non-interactively, toolchain version pinning | | [mobile](wiki/mobile/index.md) | **seeded** | App-side iOS/Android/cross-platform: process death/state survival, offline-first sync, mobile-network calls, store rollout/hotfix strategy, startup time | diff --git a/log.md b/log.md index c930fc2..d41ee15 100644 --- a/log.md +++ b/log.md @@ -43,3 +43,4 @@ Append-only. Format: `## [YYYY-MM-DD] -backup/…`) | The guardrail does not fire — the match requires a path separator after the main root — but the write is still outside the worktree; keep it out of the brief | +| The brief points the worker at a coordinator-state directory that is gitignored (`.orchestration/`, `.state/`) via a repo-relative path | The path resolves only in the main checkout: `git worktree add` checks out tracked files, so an ignored directory never materializes in a worktree. Substitute the absolute main-checkout path into the brief and state that the directory is gitignored and absent from the worktree — a capable worker otherwise hides the miss by searching for the file instead of failing | ## Instead of @@ -64,9 +65,11 @@ wait loop keeps escalating with no error from the task itself. | Put the main checkout's absolute path in a worker's `` | Give a worktree-relative path and collect the artifact from the worktree | One absolute write path halts every worker at the same phase, and the coordinator sees only a wait-loop timeout | | Disable the escape guardrail so the workers proceed | Rewrite the paths in the brief | The guardrail is what makes parallel workers safe to run against one repo | | Designate a shared scratch directory inside the repo for worker output | Place it outside the repo and pass its path as one named variable | A shared in-repo directory is both a guardrail trip and a write race between workers | +| Reuse the coordinator's repo-relative path to a gitignored state directory in a worker's prompt template | Expand it to the absolute path at substitution time and note the directory is absent from the worktree | Ignored files exist only where they were created; the relative form silently resolves to a nonexistent path in every worker, and reads of absolute main-root paths pass the guardrail | ## Sources - https://git-scm.com/docs/git-worktree — linked worktrees are separate checkouts sharing one repository; each has its own working directory - Field reproduction 2026-08-05 (groundwork guardrails 1.0.0 `hooks/bash-guard.sh`, `worktree_escape` rule, macOS): from a linked worktree, `cp ./a /b` and `echo z > /f` were both stopped; `cat /f`, `ls /.orchestration`, and `grep -n x /f` all passed. The rule matches an absolute main-root mention together with a write verb (`rm|mv|cp|tee|mkdir|touch|install|dd`) or a redirect to an absolute path - Field context: a parallel run stalled at the same phase for two workers whose brief's `` named a main-checkout absolute path; the coordinator's wait loop returned its escalation status repeatedly. Rewriting the contract to worktree-relative paths let the remaining workers record their plans locally +- Local reproduction 2026-08-13 (git 2.x, macOS): in a repo with `.gitignore` containing `.orchestration/` and a populated `.orchestration/status/`, `git worktree add ../wt1 -b wt1` produced a worktree where `ls ../wt1/.orchestration` → No such file or directory and `cat .orchestration/status/run.json` from the worktree cwd failed; `git ls-files .orchestration` → 0 tracked files. Field context: dev-loop's own `templates/session-prompt.md` handed workers `.orchestration/…` relative paths, and workers located the files by searching the main checkout rather than failing diff --git a/wiki/security/incident-response/process-identity-by-path-and-hash.md b/wiki/security/incident-response/process-identity-by-path-and-hash.md new file mode 100644 index 0000000..b3bb953 --- /dev/null +++ b/wiki/security/incident-response/process-identity-by-path-and-hash.md @@ -0,0 +1,64 @@ +--- +id: security-incident-response-process-identity-by-path-and-hash +domain: security +category: incident-response +applies_to: [macos, general] +confidence: verified +sources: + - https://attack.mitre.org/techniques/T1036/005/ +last_verified: 2026-08-13 +related: [security-incident-response-verifying-assumed-security-agents] +--- + +# A Suspicious Process Whose Name Matches a Legitimate System Daemon + +## When this applies + +You are triaging or cleaning up a host compromise (cryptominer, dropper) and a +process in `ps` output carries the name of a known system daemon — `sysmond`, +`kworker`, `svchost` — and you must decide whether to kill, quarantine, or +leave it. + +## Do this + +1. **Judge the process by its executable path and signature/hash, never by its + name.** Malware deliberately adopts legitimate daemon names (MITRE ATT&CK + T1036.005), so the name carries no identity information. +2. **Resolve the full executable path first**: `ps -axo pid,user,args` (the + `args` column shows the invocation path) or `lsof -p ` for the running + image. Then classify: + +| Executable path | Verdict | +|-----------------|---------| +| System-owned, root-only-writable location (`/usr/libexec/`, `/System/`) and the signature verifies | Legitimate — leave it | +| User-writable location (`~/.config/`, `~/Library/`, `/tmp`, a hidden dot-directory) under a system daemon's name | Malicious until proven otherwise — quarantine the file and capture it before killing | + +3. **On macOS, confirm the system-path copy with the code signature**: + `codesign -vv ` must report "valid on disk / satisfies its Designated + Requirement", and `codesign -dv ` must show an `Authority=Software + Signing` Apple chain with a `com.apple.*` identifier. A man page + (`man -w `) corroborates that the name belongs to a shipped daemon. +4. **Identify the malicious copy by its content, not its name**: hash it + (`shasum -a 256`), and read embedded strings or its own log output — a miner + typically names itself and its version in its log header. + +## Edge cases + +| Case | Then | +|------|------| +| Both a legitimate and a malicious process run under the same name simultaneously | Expected — that is the point of the masquerade; enumerate every PID for the name and classify each by its own path before killing any | +| The name matches nothing on the system (`man -w` empty, no binary at a system path) | The name itself is fabricated to look system-ish; classify by path and content as above — absence of a legitimate twin does not make it safe to name-match-kill either | +| The binary deletes itself after launch and only the process remains | `lsof -p ` still shows the mapped executable (marked deleted on Linux); capture memory/strings before killing, since the file is unrecoverable after exit | + +## Instead of + +| If you are about to | Do this instead | Why | +|---------------------|-----------------|-----| +| `pkill sysmond` because a miner cleanup guide names that process | Enumerate PIDs, resolve each executable path, kill only the user-writable-path copy | macOS ships a genuine `/usr/libexec/sysmond`; a name-based kill takes down the Apple daemon, misses a renamed miner, or both | +| Trust a process because its name has a man page | Verify the running image's path is the system path that man page documents | The masquerade works precisely because the name checks out; only the path+signature pair is identity | + +## Sources + +- https://attack.mitre.org/techniques/T1036/005/ — Masquerading: Match Legitimate Resource Name or Location; adversaries give malware "the name of a legitimate, trusted program" while placing it in a different location +- Local verification 2026-08-13 (macOS, Darwin 25.1.0): `/usr/libexec/sysmond` exists (root:wheel), `man -w sysmond` → `/usr/share/man/man8/sysmond.8`, `codesign -vv` → valid on disk / satisfies its Designated Requirement, `codesign -dv` → `Identifier=com.apple.sysmond`, `Authority=Software Signing` +- Field incident 2026-08-13: during a cryptominer cleanup, root's `/usr/libexec/sysmond` (genuine) and a quarantined `~/.config/sysmond` (XMRig 6.26.0, self-identified in its log header) coexisted under one name; path-based classification separated them where a name-based kill could not diff --git a/wiki/security/incident-response/verifying-assumed-security-agents.md b/wiki/security/incident-response/verifying-assumed-security-agents.md new file mode 100644 index 0000000..66131ea --- /dev/null +++ b/wiki/security/incident-response/verifying-assumed-security-agents.md @@ -0,0 +1,63 @@ +--- +id: security-incident-response-verifying-assumed-security-agents +domain: security +category: incident-response +applies_to: [macos, general] +confidence: verified +sources: + - https://www.elastic.co/blog/mac-system-extensions-for-threat-detection-part-3 + - https://github.com/redcanaryco/mac-monitor/wiki/5.-Endpoint-Security-Overview +last_verified: 2026-08-13 +related: [security-incident-response-process-identity-by-path-and-hash] +--- + +# A Documented Claim That a Host Runs an EDR or Security Agent + +## When this applies + +You are about to reason from a written claim (CLAUDE.md, runbook, team wiki, +onboarding doc) that a host runs an EDR/security agent — judging whether a +threat "would have been detected", triaging a suspected compromise, or applying +rules premised on the agent's presence. + +## Do this + +1. **Verify the agent is installed and running on the host before using the + document as evidence.** On macOS, check all three together — each alone can + miss: + +| Check | Command | What it catches | +|-------|---------|-----------------| +| Vendor install directory | `ls -d /Library/Sentinel*` (adjust to the vendor's documented path) | Agent files present at all | +| Running processes | `ps aux \| grep -iE "sentinel\|crowdstrike\|falcon\|defender"` | Agent daemons actually executing | +| System extensions | `systemextensionsctl list` | Endpoint Security clients — since macOS 10.15 deprecated kexts, EDR vendors ship ES clients as system extensions, so a real EDR appears here even when its process names don't match your grep | + +2. **When all three come back empty, conclude "not installed" — not "failed to + detect".** The two conclusions produce opposite threat models: "installed but + silent" reads as an agent-evading advanced threat; "absent" reads as an + ordinary threat on an undefended host. + +3. **Update the document that carried the stale claim** in the same session, so + the next reader does not re-derive the wrong threat model from it. + +## Edge cases + +| Case | Then | +|------|------| +| The extension appears in `systemextensionsctl list` but its state is not `[activated enabled]` | The agent is installed but not intercepting — the user never approved it, or it was deactivated; treat detection coverage as absent until the state shows activated | +| The document's claim was true once (agent since removed or license lapsed) | This is the expected failure mode, not an exception — documents record install state at writing time and rot silently; that is why the host, not the document, is the source of truth | +| The host is not macOS | The principle holds; verify through the vendor's documented service mechanism for that OS (service units, installed packages) rather than a process grep alone | + +## Instead of + +| If you are about to | Do this instead | Why | +|---------------------|-----------------|-----| +| Conclude "the EDR didn't flag it, so the binary is clean" from a doc that says an EDR is present | Run the three checks; only an agent proven present and activated can clear anything | On the incident that produced this page, docs claimed SentinelOne while all three checks were empty — a root XMRig miner had run 4 days 8 hours on a host with no EDR at all | +| Write a security rule justified by "the EDR will catch X" | Verify presence first, and cite the check output in the rule | A rule premised on an absent control enforces nothing and blocks the real question | + +## Sources + +- https://www.elastic.co/blog/mac-system-extensions-for-threat-detection-part-3 — macOS security vendors must use Endpoint Security via system extensions after kext deprecation; extensions are enumerable on the host +- https://github.com/redcanaryco/mac-monitor/wiki/5.-Endpoint-Security-Overview — Endpoint Security framework as the sanctioned interception point for EDR/antivirus on macOS +- Local verification 2026-08-13 (macOS, Darwin 25.1.0): `systemextensionsctl list` enumerated the machine's extensions (one DriverKit entry, no ES clients), `ls -d /Library/Sentinel*` → no matches, process grep → 0 — consistent with the incident finding that the documented SentinelOne was never installed +- Field incident 2026-08-13: global CLAUDE.md cited "SentinelOne EDR detects this" as a rule's rationale; the three checks returned empty on the machine and a root-privileged XMRig had run 4d8h undetected — the document's premise, not the miner's sophistication, was the gap diff --git a/wiki/security/index.md b/wiki/security/index.md index 9c6ec2c..f1e78ea 100644 --- a/wiki/security/index.md +++ b/wiki/security/index.md @@ -2,8 +2,9 @@ Route here for: trust-boundary decisions — input validation, authn approach choice, per-resource authorization, secrets hygiene, dependency trust, PII -handling. Mechanics owned elsewhere are linked: XSS rendering → frontend, -CI secrets → infrastructure, JWT implementation → backend/frontend auth. +handling — and live host-compromise triage (incident response). Mechanics owned +elsewhere are linked: XSS rendering → frontend, CI secrets → infrastructure, +JWT implementation → backend/frontend auth. Match your situation to a "load when" line; load only matching pages. @@ -44,6 +45,13 @@ Match your situation to a "load when" line; load only matching pages. |------|-----------| | [supply-chain](dependencies/supply-chain.md) | Adding a dependency (add-vs-write decision, name verification, install scripts); updating dependencies (auto-update PRs, major versions, transitive CVE overrides); hardening against malicious/compromised packages (lockfiles, reproducible installs) | +## incident-response + +| Page | Load when | +|------|-----------| +| [verifying-assumed-security-agents](incident-response/verifying-assumed-security-agents.md) | About to reason from a documented claim (CLAUDE.md, runbook, wiki) that a host runs an EDR/security agent — judging whether a threat "would have been detected", triaging a suspected compromise, or applying rules premised on the agent's presence | +| [process-identity-by-path-and-hash](incident-response/process-identity-by-path-and-hash.md) | Triaging or cleaning up a host compromise and a process name in `ps` matches a known system daemon (`sysmond`, `kworker`); deciding whether to kill, quarantine, or leave a suspicious-named process | + ## data | Page | Load when |