Security findings 3
Persistence
highOverreachConfirmed on reviewmedium confidenceThe guide tells the agent, when it can edit its own persistent config, to replace the pasted instructions copy in CLAUDE.md or the instructions file with the install's fetched guide, writing to an agent-wide memory or rules surface beyond what the status and agents_md reads need.
replace the pasted copy so future sessions start current.
vector:instruction
Reviewer's reasoning
The guide tells the agent to replace the pasted instructions in its persistent CLAUDE.md or instructions file with the fetched guide, writing to an agent-wide memory surface beyond the read-only status and agents_md purpose. The carve-out that the step is conditional on the agent's own capability does not remove the agent-wide write.
Persistence
highOverreachConfirmed on reviewhigh confidenceThe periscope_system agents_md action tells the agent to overwrite the user's persistent CLAUDE.md or agent instructions file with the tool's pasted content, so runtime tool output changes agent-wide rules beyond the declared read-only guide fetch.
replace the pasted copy with this content so FUTURE sessions
vector:instruction
Reviewer's reasoning
The agents_md tool response tells the agent to overwrite the user's persistent CLAUDE.md or instructions file with its content, changing agent-wide rules beyond the declared read-only guide fetch.
Privilege escalation
mediumOverreachConfirmed on reviewmedium confidenceThe update action's options tell the agent it may re-run with force=true, which stashes the user's uncommitted local changes in the install repo after the tool asked the user to choose, so the agent can take that step without the user's decision.
re-run with force=true — changes are stashed (git stash),
vector:instruction
Reviewer's reasoning
The update action's dirty-file check is a confirmation gate, and passing force=true bypasses it so the agent can stash the user's uncommitted changes without a user decision. The stash is recoverable, but the gate is still worked around.
Notes 15
Capabilities, vulnerabilities and disclosed behavior worth knowing. Nothing here works against the person who installs it, so notes never change the verdict.
Code execution
highNoteConfirmed on reviewmedium confidenceWhen Node is missing, run_lighthouse's error response tells the user to run a curl-piped-to-bash installer for nvm from a third-party repository pinned to a tag; the user is shown and runs it, so this is a note.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
conceal:remotevector:instruction
Reviewer's reasoning
The error response only prints an nvm install command from a pinned tag of the official nvm repository. The tool does not run it, and the user chooses whether to run it, so this is a user-decided step.
Credential access
mediumNoteConfirmed on reviewmedium confidenceget_cookies returns every cookie of the session to the calling agent's context; the cookie read is the tool's declared purpose, so this is a note, not a concealed transfer.
cookies = await real_page(session.page).context.cookies()
vector:code
Reviewer's reasoning
get_cookies returns cookies to the calling agent as its declared purpose. No host receives them, so this is the declared core capability, not an exfiltration.
Credential access
mediumNoteConfirmed on reviewlow confidencerun_lighthouse copies the full process environment into the Lighthouse subprocess environment; this is undeclared but needed to launch node and Chrome, and no path sends it off-host, so it is a note.
env = dict(os.environ)
vector:code
Reviewer's reasoning
The Lighthouse subprocess inherits the full environment, which is needed to locate node and Chrome. No code sends the environment off-host, so this is hygiene rather than exfiltration.
Persistence
mediumNoteConfirmed on reviewhigh confidenceThe installer prints client-config paths and tells the user to merge the Periscope server entry into ~/.cursor/mcp.json and ~/.codex/config.toml; the user performs the edit, so this is a note.
merge into ~/.cursor/mcp.json
vector:instruction
Reviewer's reasoning
The installer prints paths and tells the user to merge the entry into the client config. The user performs the edit, so this is a user-decided step.
Credential access
mediumNoteConfirmed on reviewhigh confidenceThe project store writes form-login passwords, basic-auth passwords and session cookies as plaintext into projects.json; the artifact discloses this and restricts the file to owner-only permissions, so it is a local hygiene note.
file holds plaintext credentials, so keep it owner-only.
vector:code
Reviewer's reasoning
The quote matches the code comment, which says the file holds plaintext credentials and is restricted to owner-only permissions (0o600). Storing a user's own credentials locally is a hygiene note, and nothing sends the file anywhere.
Credential access
mediumNoteConfirmed on reviewlow confidenceThe web_fetch tool with project set loads a URL in that project's authenticated browser context, so the logged-in session is available to whatever URL the caller supplies; this is a declared feature and needs an attacker-steered URL to misuse.
pass project to render a page behind that project's login
Reviewer's reasoning
The project-authenticated render is a declared feature. Misuse needs a caller or page to steer the URL, which is outside input, so it is a note under test 3.
Credential access
mediumNoteConfirmed on reviewmedium confidenceThe get_cookies tool returns full cookie name and value pairs from the session browser context to the agent, a declared debugging purpose that exposes session cookies within the user's own test session.
Read all cookies from a session's browser context
Reviewer's reasoning
get_cookies is a declared debugging tool that returns cookies to the agent in the user's own test session. Nothing in the shown code sends them to another host, so this is a note.
Supply chain
lowNoteConfirmed on reviewmedium confidenceLighthouse is launched via unpinned npx --yes from the public npm registry as a fallback when no global install exists; this is a note for a third-party package from an official registry.
return [npx, "--yes", "lighthouse"], bin_dir, npm_tip
vector:code
Reviewer's reasoning
Lighthouse is launched via npx from the public npm registry as a fallback. This is a third-party package from an official registry, which is a note under the carve-outs.
Agent hijacking
lowNoteConfirmed on reviewmedium confidenceThe describe_tools tips steer the agent to fetch the current operating guide from the install via periscope_system agents_md when its pasted copy may be stale; that remote text can replace the reviewed instructions the agent follows, which is an overreach (remote control of operating instructions), with the apply-approval step mitigating only the update action.
action='agents_md' returns the CURRENT operating guide if your pasted copy may be stale.
vector:instruction
Reviewer's reasoning
The claimed remote text is wrong: agents_md reads the install's own shipped AGENTS.md from disk, not a remote source. The tip only suggests a conditional local read, so the remote-control overreach does not hold. The write-to-memory concern is covered by findings 1 and 9.
Supply chain
lowNoteConfirmed on reviewlow confidenceThe status action is documented as read-only, but its _update_check helper runs git fetch against origin on every call, updating remote refs; a note-level mismatch with the declared read-only claim.
code, out = await _git("fetch", "--quiet", "origin", timeout=15)vector:code
Reviewer's reasoning
The status action runs git fetch against origin, which updates remote refs. This is a mismatch with the read-only label, but it fetches the publisher's own repository and is hygiene, not harm.
Privilege escalation
lowNoteConfirmed on reviewmedium confidenceWhen system packages are missing, install_debian runs sudo apt-get install after a confirmation prompt that --yes skips; the user invokes the installer and opts in, so this is a note.
sudo apt-get install -y "${need_pkgs[@]}"vector:code
Reviewer's reasoning
The user runs the installer and opts into installing missing system packages, with a confirm prompt. The confirm helper is not shown, so the claimed --yes bypass is unverified, but the user chose to run the installer.
Privilege escalation
lowNoteConfirmed on reviewmedium confidenceThe Playwright install-deps step runs under sudo after a confirmation prompt that --yes skips; the user runs the installer and opts in, so this is a note.
sudo "$VENV/bin/python" -m playwright install-deps chromium
vector:code
Reviewer's reasoning
The installer runs playwright install-deps under sudo only after a confirm prompt during the user-run installer. This is a user-decided prerequisite step for the artifact's own browser.
Supply chain
lowNoteConfirmed on reviewmedium confidenceThe periscope_system update action with apply=true runs a git pull and dependency install of the publisher's own repository, a user-invoked self-update that is disclosed in the tool description.
apply=true runs the updater (git pull + deps, data/ untouched)
Reviewer's reasoning
apply=true is an explicit user-invoked update of the publisher's own repository, and the description discloses the git pull. This matches the carve-out for the publisher's own code fetched on the user's instruction.
Supply chain
lowNoteConfirmed on reviewmedium confidenceupdate.sh pulls the publisher's own repository from origin with git pull and then re-runs its own installer; this fetches the artifact's own code, so it is a note.
git pull --ff-only
vector:code
Reviewer's reasoning
update.sh runs git pull --ff-only against the artifact's own origin, which is the publisher's repository and is the artifact's own update path. This matches the carve-out for the artifact's own code.
Privilege escalation
lowNoteConfirmed on reviewmedium confidenceupdate.sh runs install.sh with -y, which auto-accepts sudo and apt confirmation prompts when the user runs the full update with --full; the user chose to run the update, so this is a note.
INSTALL_ARGS=(-y)
vector:code
Reviewer's reasoning
The -y is passed only when the user runs update.sh, and --full is documented as re-running the apt prerequisite flow with sudo, so the sudo steps are user-invoked and disclosed; the confirmation skip is a user-opted convenience, not an artifact-initiated overreach. Note under test 4.