fix(security): GHSA-gvpp-v77h-5w8g — untrusted dev-source ACE#47
Merged
Conversation
The open_visualization tool resolved candidate Cortex dev-source roots
via the CLAUDE_PROJECT_DIR env var (set automatically by Claude Code to
whichever project the user has open). A candidate qualified iff it
contained a trivial two-marker pair — an mcp_server/ subdirectory and a
ui/unified-viz.html file — that any attacker can replicate in a
malicious repository. The handler then subprocess.run([sys.executable,
str(bootstrap_path)]) against mcp_server/server/visualize_bootstrap.py
inside the qualifying directory, yielding local arbitrary code
execution with the privileges of the victim's user process.
A secondary code-execution path went through http_launcher._detect_dev_
source which mirrored the same env-var ordering; the launcher rsyncs
the returned dev source over the package path and respawns the
visualization server from the synced copy.
Reported by EQSTLab (SK Shieldus security research) on 2026-05-27.
CVSS v3.1 base 7.8 (HIGH). Vulnerable range: ≤ 3.17.0.
Hardening (per advisory recommendation):
* CLAUDE_PROJECT_DIR is no longer consulted by either function.
* CORTEX_DEV_ROOT is consulted only when the user has also set
CORTEX_DEV_SOURCE_SYNC=1 — an explicit opt-in that signals
"I deliberately want my CORTEX_DEV_ROOT to be used as a
code-execution dev source."
* The exact string "1" is required to activate the gate (so an
accidental "true"/"yes" in a shell rc file cannot silently
re-open the hole).
* Launcher's filesystem-position auto-detect ("walk up from the
launcher module's own location") is preserved — an attacker
would need write access to the user's site-packages to abuse
it, which is a strictly higher-privilege precondition than the
exploit it would yield.
* Conventional ~/Documents/Developments/Cortex fallback is
preserved — user-controlled filesystem; attacker would already
need write access under $HOME to abuse it.
Falsification tests added in tests_py/handlers/test_open_visualization
.py::TestDevSourceSecurityHardening and tests_py/server/test_http_
launcher_security.py::TestDetectDevSourceSecurityHardening — 7 tests,
all green. Each test plants the two marker files plus the bootstrap
PoC into a tempdir, points the relevant env var at it, and asserts
the function refuses to return it.
Version bumped to 3.17.1.
source: GHSA-gvpp-v77h-5w8g
EQSTLab, "Untrusted Project Bootstrap Code Execution via
CLAUDE_PROJECT_DIR" (2026-05-27).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI lint job flagged F401 on the added security regression tests in PR #47. Both imports were leftovers from an earlier iteration that used monkeypatch-as-fixture imperatively; the final tests use the pytest-injected monkeypatch fixture and tempfile, neither of which requires the os or pytest top-level imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cdeust
added a commit
that referenced
this pull request
May 27, 2026
…lace v3.17.1 shipped the security fix CODE to the marketplace, but the release only bumped pyproject.toml — .claude-plugin/marketplace.json still advertised 3.17.0. Because Claude Code decides whether to prompt a /plugin update by comparing the installed version against the marketplace-advertised version, users sitting on 3.17.0 were never prompted to pull the fix, even though it was present in the cloned tree. The patched code was in the channel but unadvertised. This bump aligns all version labels at 3.17.2 so the marketplace advertises an increment and the update prompt fires: - .claude-plugin/marketplace.json metadata.version 3.17.0 -> 3.17.2 - .claude-plugin/marketplace.json plugins[0].version 3.17.0 -> 3.17.2 - pyproject.toml version 3.17.1 -> 3.17.2 - added plugins[0].version_note pointing at the advisory No code change — the fix already landed in 5d22091 (PR #47). This is purely the distribution-metadata correction that makes the marketplace (the only supported install path per ADR-0050) surface it as an update. source: GHSA-gvpp-v77h-5w8g; ADR-0050 (marketplace-only distribution). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the local arbitrary code execution vulnerability GHSA-gvpp-v77h-5w8g reported by EQSTLab on 2026-05-27. CVSS v3.1 base 7.8 (High). Vulnerable range:
neuro-cortex-memory ≤ 3.17.0.Threat model (verbatim from advisory)
_find_dev_source()inmcp_server/handlers/open_visualization.pyacceptedCLAUDE_PROJECT_DIR(set automatically by Claude Code to whatever project the user has open) as a candidate Cortex dev-source root. A candidate qualified iff it contained a trivial two-marker pair —mcp_server/subdirectory +ui/unified-viz.htmlfile — that any attacker can replicate.The handler then
subprocess.run([sys.executable, str(bootstrap_path)])against<dev_src>/mcp_server/server/visualize_bootstrap.pyinside the qualifying directory, yielding local arbitrary code execution with the privileges of the victim's user process.Two secondary surfaces:
mcp_server/server/http_launcher.py::_detect_dev_sourcemirrored the same env-var ordering and rsyncs the returned dev source over the package path before respawning the server from the synced copy.mcp_server/server/visualize_bootstrap.py::_find_dev_source(invoked as a subprocess of the handler) inherited the parent process env and re-resolvedCLAUDE_PROJECT_DIR→ same rsync-overwrite path → persistent ACE.Hardening
Three functions (
open_visualization._find_dev_source,http_launcher._detect_dev_source,visualize_bootstrap._find_dev_source) now apply the same gate:CLAUDE_PROJECT_DIRis no longer consulted in any of them.CORTEX_DEV_ROOTis consulted only whenCORTEX_DEV_SOURCE_SYNC=1is set as an explicit opt-in — exact string"1"required (so an accidental"true"/"yes"in a shell rc file cannot silently re-open the hole).~/Documents/Developments/Cortexfallback remains (user-controlled filesystem).Verification
bootstrap='no_dev_source', sentinel file never created, no rsync, no subprocess against the attacker path.CORTEX_DEV_SOURCE_SYNC=1+CORTEX_DEV_ROOTpointing at a real checkout): still works, bootstrap fires as expected.tests_py/handlers/test_open_visualization.py::TestDevSourceSecurityHardening(4 tests — handler)tests_py/server/test_http_launcher_security.py::TestDetectDevSourceSecurityHardening(3 tests — launcher)tests_py/server/test_http_launcher_security.py::TestBootstrapFindDevSourceSecurityHardening(3 tests — bootstrap subprocess)open_visualizationsuite: 17/17 passing (4 pre-existing + 13 new).automatised-pipeline,ai-prd-generator,ai-prd-generator-plugin,zetetic-team-subagents): clean of the same class of vulnerability (noCLAUDE_PROJECT_DIRconsumption, no env-derivedsubprocess.run/Command::new, no marker-file validation followed by exec).Release plan
After merge:
v3.17.1onmain3.17.0from PyPI with reason citing GHSA-gvpp-v77h-5w8gCredit
Reported by @EQSTLab (Experts, Qualified Security Team — SK Shieldus). Coordinated disclosure via private GHSA draft, complete with structured PoC and a precise remediation diff. Thanks for the careful, rigorous report.
source: GHSA-gvpp-v77h-5w8g
🤖 Generated with Claude Code