chore: import upstream snapshot with attribution
CI / test (20, macos-latest) (push) Has been cancelled
CI / test (20, ubuntu-latest) (push) Has been cancelled
CI / test (22, macos-latest) (push) Has been cancelled
CI / test (22, ubuntu-latest) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:01:18 +08:00
commit 979fb22d7c
613 changed files with 113494 additions and 0 deletions
@@ -0,0 +1,46 @@
# GHSA Draft: Stored XSS in agentmemory real-time viewer
**Severity:** Critical · **CVSS 3.1:** 9.6 (`AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:L`)
**CWE:** [CWE-79 — Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
agentmemory's real-time viewer (default port 3113) rendered user-controlled data — tool outputs, file paths, memory titles, observation content — into HTML using inline `onclick=` event handlers. The viewer's Content Security Policy simultaneously allowed `script-src 'unsafe-inline'`, meaning injected JavaScript would execute in the reader's browser context.
## Impact
Any data captured by agentmemory hooks — which includes tool output from Claude Code, Cursor, or any other agent — becomes an XSS vector when the user opens the viewer. An attacker with the ability to influence any captured observation (e.g., by sending a crafted file contents to be read by an agent, or by planting a malicious commit message in a repository) could:
- Exfiltrate the entire memory store via authenticated requests from the browser
- Read `AGENTMEMORY_SECRET` if the viewer was configured with auth
- Make requests to arbitrary endpoints on behalf of the viewer user
- Modify the DOM to mislead the developer
- Pivot to other localhost services on the developer's machine
The viewer runs on localhost by default but is **reachable from the browser**, so standard same-origin protections don't help.
## Patches
Fixed in **0.8.2**:
- All inline `on*=` handlers removed from `src/viewer/index.html`
- Replaced with delegated `data-action` event handling
- CSP switched to a **per-response script nonce** (`script-src 'nonce-<random>'`)
- Added `script-src-attr 'none'` to block any inline handler attributes even if injected
- Viewer HTML now rendered through `src/viewer/document.ts` which generates a fresh nonce per request
## Workarounds
**None.** Users on affected versions should upgrade to 0.8.2 immediately. Do not open `http://localhost:3113` in a browser on affected versions if you suspect any of your captured observations may contain attacker-controlled content.
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
- Reporter: @eng-pf
## Credit
@eng-pf submitted PR #108 with fixes for this and 5 other vulnerabilities.
@@ -0,0 +1,57 @@
# GHSA Draft: Remote shell script execution in agentmemory CLI startup
**Severity:** Critical · **CVSS 3.1:** 9.8 (`AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`)
**CWE:** [CWE-494 — Download of Code Without Integrity Check](https://cwe.mitre.org/data/definitions/494.html), [CWE-829 — Inclusion of Functionality from Untrusted Control Sphere](https://cwe.mitre.org/data/definitions/829.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
The agentmemory CLI (`npx @agentmemory/agentmemory`) auto-installed the iii-engine binary by piping a remote shell script into `sh`:
```ts
execSync("curl -fsSL https://install.iii.dev/iii/main/install.sh | sh")
```
This happened automatically on first run if `iii` was not found in `$PATH`. The script was fetched over HTTPS and executed with the permissions of the user running `npx agentmemory`. No checksum verification, no pinned version, no signature check.
## Impact
If `install.iii.dev` were ever compromised — via DNS hijack, domain takeover, expired certificate + MITM on an untrusted network, BGP attack, or any other supply chain attack — **every new agentmemory user would execute attacker-controlled shell code** as their own user.
This is the canonical "curl | sh" supply chain anti-pattern. It affected:
- Developers running `npx @agentmemory/agentmemory` for the first time
- CI/CD pipelines that installed agentmemory fresh
- Docker builds that installed agentmemory as part of an image
## Patches
Fixed in **0.8.2**:
- Removed `execSync` call entirely from `src/cli.ts`
- CLI now uses an existing local `iii` binary if present in `$PATH`
- Falls back to Docker Compose (`docker compose up -d`) if Docker is available
- Shows manual install instructions if neither iii nor Docker is found:
- `cargo install iii-engine`
- `docker pull iiidev/iii:latest`
- Docs link: https://iii.dev/docs
## Workarounds
Users on affected versions should **install iii-engine manually** and run `agentmemory --no-engine` until upgraded:
```bash
cargo install iii-engine
npx @agentmemory/agentmemory@0.8.1 --no-engine
```
Then upgrade to 0.8.2 at the earliest opportunity.
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
## Credit
@eng-pf
@@ -0,0 +1,62 @@
# GHSA Draft: agentmemory REST and stream services bound to 0.0.0.0 by default
**Severity:** High · **CVSS 3.1:** 8.1 (`AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L`)
**CWE:** [CWE-668 — Exposure of Resource to Wrong Sphere](https://cwe.mitre.org/data/definitions/668.html), [CWE-306 — Missing Authentication for Critical Function](https://cwe.mitre.org/data/definitions/306.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
The default `iii-config.yaml` bound both the REST API (port 3111) and the streams server (port 3112) to `0.0.0.0`, exposing them on every network interface the host could reach. Combined with the fact that `AGENTMEMORY_SECRET` is **unset by default**, this meant any device on the same local network as a running agentmemory instance could read the entire memory store without authentication.
Affected endpoints included:
- `GET /agentmemory/export` — full dump of every captured observation, memory, session, and audit entry
- `GET /agentmemory/sessions` — session list
- `POST /agentmemory/smart-search` — arbitrary search over all captured content
- `POST /agentmemory/observe` — ability to **inject** fake observations
- `POST /agentmemory/remember` — ability to plant arbitrary memories
- All 109 other REST endpoints
## Impact
A developer running agentmemory on a laptop in a coffee shop, office, or conference WiFi effectively published their entire memory store — including captured API keys, file contents, prompts, decisions, and project context — to anyone on the same network.
Attackers on the same network could:
1. **Exfiltrate secrets.** `curl http://<victim-ip>:3111/agentmemory/export` downloads everything. Depending on the incompleteness of the secret redaction (see advisory #06), this could include API keys and tokens.
2. **Inject memories.** An attacker could `POST /agentmemory/observe` or `/remember` with fake observations, poisoning the memory store so future sessions retrieve attacker-controlled context.
3. **Pivot to other services.** The mesh sync endpoint (before the auth fix in advisory #04) accepted peer data from any source.
## Patches
Fixed in **0.8.2**:
- `iii-config.yaml` now binds REST, streams to `127.0.0.1`
- Viewer server already bound to `127.0.0.1`
- New `iii-config.docker.yaml` for Docker deployments: containers bind to `0.0.0.0` internally (required for Docker networking) but host port mapping is restricted to `127.0.0.1:port` in `docker-compose.yml`
- README and API section documentation updated to note 127.0.0.1 as the default
## Workarounds
Users on affected versions should manually edit their `iii-config.yaml` and change the REST and streams `host` values to `127.0.0.1`:
```yaml
modules:
- class: modules::api::RestApiModule
config:
host: 127.0.0.1 # was 0.0.0.0
- class: modules::stream::StreamModule
config:
host: 127.0.0.1 # was 0.0.0.0
```
And set `AGENTMEMORY_SECRET` to a strong random value to protect endpoints even if network exposure is needed.
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
## Credit
@eng-pf
@@ -0,0 +1,47 @@
# GHSA Draft: Unauthenticated mesh sync in agentmemory
**Severity:** High · **CVSS 3.1:** 7.4 (`AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N`)
**CWE:** [CWE-306 — Missing Authentication for Critical Function](https://cwe.mitre.org/data/definitions/306.html), [CWE-862 — Missing Authorization](https://cwe.mitre.org/data/definitions/862.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
agentmemory's mesh federation feature (P2P sync between instances) accepted push/pull requests on its `/agentmemory/mesh/*` endpoints without requiring authentication. The mesh sync function also did not send any `Authorization` header when calling peer instances, meaning the federation protocol was entirely unauthenticated.
## Impact
Any attacker who could reach a mesh-enabled agentmemory instance could:
1. **Push fake memories** via `POST /agentmemory/mesh/receive` — inject attacker-controlled observations, actions, semantic memories, and relations into the target's memory store. This poisons future retrievals and could be used to manipulate what the target's AI agent sees.
2. **Pull the entire memory store** via `GET /agentmemory/mesh/export` — download all memories, actions, and graph data marked as mesh-shareable.
3. **Chain with advisory #03** — combined with the default `0.0.0.0` binding, mesh endpoints were reachable from any device on the local network without any authentication.
Mesh is opt-in (requires an explicit peer registration), so this affected only users who had enabled federation. But those users had no authentication at all.
## Patches
Fixed in **0.8.2**:
- All 5 mesh REST endpoints (`mesh-register`, `mesh-list`, `mesh-sync`, `mesh-receive`, `mesh-export`) now return 503 with `"mesh requires AGENTMEMORY_SECRET"` if the secret is not configured
- The `mem::mesh-sync` function now accepts a `meshAuthToken` parameter and **refuses to sync at all** if the token is missing
- Outgoing push/pull requests include `Authorization: Bearer <secret>` headers
- Server-side, all mesh endpoints check bearer auth via the existing `checkAuth` helper
## Workarounds
Users on affected versions who have mesh federation enabled should:
1. Set `AGENTMEMORY_SECRET` to a strong random value on **both** peers
2. Restart the server
3. Upgrade to 0.8.2 at the earliest opportunity
Users who have **not** enabled mesh federation are not affected by this specific issue, but should still upgrade for the other 5 fixes.
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
## Credit
@eng-pf
@@ -0,0 +1,61 @@
# GHSA Draft: Arbitrary filesystem write via Obsidian export in agentmemory
**Severity:** Medium · **CVSS 3.1:** 6.5 (`AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L`)
**CWE:** [CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')](https://cwe.mitre.org/data/definitions/22.html), [CWE-73 — External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
The `POST /agentmemory/obsidian/export` endpoint accepted a `vaultDir` parameter and passed it directly to `mkdir` and `writeFile` calls without any containment check. A caller could set `vaultDir` to any absolute path on the filesystem and agentmemory would create directories and write Markdown files there with the permissions of the process running the server.
```bash
# Example exploit payload (affected versions only)
curl -X POST http://localhost:3111/agentmemory/obsidian/export \
-H "Content-Type: application/json" \
-d '{"vaultDir": "/etc/cron.d"}'
```
The content written would be agentmemory's exported memories in Markdown format, but an attacker could craft specific memory content beforehand to plant arbitrary files.
## Impact
When chained with advisory #03 (default `0.0.0.0` binding) or advisory #04 (unauthenticated mesh), an attacker on the local network could write arbitrary files to any filesystem location the agentmemory process had write access to.
Possible exploitation paths:
- Write to `~/.ssh/authorized_keys` — SSH key injection
- Write to `/etc/cron.d/*` — cron job injection (if running as root)
- Write to `~/.bashrc` or shell rc files — code execution on next shell
- Overwrite any file the process could write to
## Patches
Fixed in **0.8.2**:
- New `AGENTMEMORY_EXPORT_ROOT` environment variable (default: `~/.agentmemory`)
- `vaultDir` now goes through `resolveVaultDir()` in `src/functions/obsidian-export.ts`:
- Resolves the path with `path.resolve`
- Checks `resolved === root || resolved.startsWith(root + path.sep)`
- Returns `null` if the check fails, and the endpoint returns `{ success: false, error: "vaultDir must be inside AGENTMEMORY_EXPORT_ROOT" }`
- Default export is confined to `~/.agentmemory/vault`
- Tests added in `test/obsidian-export.test.ts` for both the custom-but-valid case and the rejection case
## Known limitations
`resolveVaultDir()` performs lexical containment only — it does not call `fs.realpathSync` / `fs.lstatSync`. A pre-existing symlink under `AGENTMEMORY_EXPORT_ROOT` that points outside the root can still be written through. Users who allow untrusted processes to create files inside `AGENTMEMORY_EXPORT_ROOT` should additionally run agentmemory inside a sandbox that forbids symlink creation, or file a follow-up issue requesting symlink-aware containment.
## Workarounds
Users on affected versions should:
1. **Disable the Obsidian export endpoint** by setting `OBSIDIAN_AUTO_EXPORT=false` (and avoid calling `/agentmemory/obsidian/export` manually)
2. Set `AGENTMEMORY_SECRET` so the endpoint requires bearer auth
3. Upgrade to 0.8.2
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
## Credit
@eng-pf
@@ -0,0 +1,60 @@
# GHSA Draft: Incomplete secret redaction in agentmemory privacy filter
**Severity:** Medium · **CVSS 3.1:** 6.2 (`AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N`)
**CWE:** [CWE-532 — Insertion of Sensitive Information into Log File](https://cwe.mitre.org/data/definitions/532.html), [CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/200.html)
**Affected versions:** `< 0.8.2`
**Patched version:** `0.8.2`
## Summary
agentmemory's privacy filter (`src/functions/privacy.ts`) is supposed to strip API keys, secrets, and bearer tokens from captured observations before they are stored. The filter used regex patterns to detect common token formats. Three modern token formats were missing from the patterns:
1. **Bearer tokens**`Authorization: Bearer <token>` headers were not matched, so any captured HTTP request or response that included an Authorization header flowed into the memory store verbatim.
2. **OpenAI project keys**`sk-proj-*` (the dominant OpenAI API key format since mid-2024) was not matched. The existing `sk-[A-Za-z0-9]{20,}` pattern only caught the legacy format.
3. **GitHub fine-grained service/user tokens**`ghs_*` and `ghu_*` were not matched. The existing `ghp_[A-Za-z0-9]{36}` pattern only caught personal access tokens.
## Impact
agentmemory's README explicitly claimed "Privacy first — API keys, secrets, and `<private>` tags are stripped before anything is stored." That claim was **false** for three common token formats.
Users relying on the privacy filter to protect their captured observations had a false sense of security. Tokens matching these three patterns would:
1. Be captured by `PostToolUse` hooks alongside the rest of the tool output
2. Pass through `stripPrivateData()` unmodified
3. Be LLM-compressed and stored in the memory KV
4. Be exposed to any attacker who could reach the `/agentmemory/export` or `/agentmemory/smart-search` endpoints
5. Be included in Obsidian exports, mesh syncs, and CLAUDE.md bridge writes
When chained with advisory #03 (default `0.0.0.0` binding), this meant network-adjacent attackers could retrieve captured Bearer tokens, OpenAI keys, and GitHub service tokens from the memory store.
## Patches
Fixed in **0.8.2**:
New regex patterns added to `SECRET_PATTERN_SOURCES` in `src/functions/privacy.ts`:
```ts
/Bearer\s+[A-Za-z0-9._\-+/=]{20,}/gi,
/sk-proj-[A-Za-z0-9\-_]{20,}/g,
/(?:sk|pk|rk|ak)-[A-Za-z0-9][A-Za-z0-9\-_]{19,}/g,
/gh[pus]_[A-Za-z0-9]{36,}/g,
```
Three new unit tests in `test/privacy.test.ts` verify each format is now stripped.
## Workarounds
Users on affected versions should:
1. Avoid having agents read files or API responses containing these token formats
2. Use the `<private>` tag around any block containing secrets — that filter was not affected
3. Set `AGENTMEMORY_SECRET` to restrict API access
4. Upgrade to 0.8.2
## References
- Fix PR: [#108](https://github.com/rohitg00/agentmemory/pull/108)
- Commit: [`cbaaf4f`](https://github.com/rohitg00/agentmemory/commit/cbaaf4f)
## Credit
@eng-pf