Announcing Beacon: Self-improving memory for coding agents
← All MCP servers
MCP server

io.github.saiffmirza/kiyas

mcp:saiffmirza/kiyas

AI design fidelity — compare Figma designs or screenshots against rendered UI. No API keys.

Verdict
Inconclusive

The analysis could not cover enough of the artifact to decide.

Analyzed Oct 29, 2026, 16:09 UTC at 4b43708

Dispute security verdict

If you believe this verdict is incorrect, submit a dispute and we'll review it.

0
findings
—
highest severity
0
threat classes
109
files scanned
528/528
checks satisfied
0
package advisories

Why this verdict

mcp-server . Inconclusive
  • benign: 484 checks satisfied, nothing works against the installer of mcp-server:. (13 notes, 0 third-party flags)
mcp-server packages/cli Inconclusive
  • inconclusive: unresolved question on CRED

Security findings 0

No individual findings recorded

The inconclusive verdict rests on the open questions below.

Notes 18

Capabilities, vulnerabilities and disclosed behavior worth knowing. Nothing here works against the person who installs it, so notes never change the verdict.

Credential access

highNoteConfirmed on reviewmedium confidence

The embedded terminal's shell is spawned with the app's full process environment, which can include tokens; this is the user's own shell with no off-host transmission, so it is a hygiene note.

Object.entries(process.env)
vector:code
Reviewer's reasoning

The embedded terminal passes the environment to the user's own local shell with no off-host transmission, so this is a hygiene note.

Code execution

mediumNoteConfirmed on reviewmedium confidence

A desktop setup action the user clicks opens Terminal and runs a global npm install of the vendor CLI (claude or codex) before launching it; a user-invoked setup step, noted only.

command -v claude >/dev/null 2>&1 || npm install -g @anthropic-ai/claude-code; claude
vector:code
Reviewer's reasoning

The global npm install of the vendor CLI runs only when the user clicks the setup action and sees a Terminal window, so it is a user-invoked step.

Code execution

mediumNoteConfirmed on reviewmedium confidence

At startup the desktop app runs the user's login shell to read PATH and patches process.env; this is a declared hygiene behavior for finding CLIs and is a note.

login-shell PATH once and patch process.env before anything spawns.
vector:code
Reviewer's reasoning

Reading the login-shell PATH to find CLIs is the declared purpose of the startup fix and changes only the app's own process environment.

Code execution

mediumNoteConfirmed on reviewlow confidence

The desktop app opens a Terminal running install commands for AI provider CLIs when the user clicks the provider or browser setup action; the user invokes and sees it, so it is a note.

Opens Terminal running the install + sign-in flow for a provider or the screenshot browser.
vector:instruction
Reviewer's reasoning

The shipped comment states the Terminal install flow is triggered by the user's setup action, so it is a user-invoked step and a note.

Credential access

mediumNoteConfirmed on reviewmedium confidence

The ensureFigmaToken flow writes a pasted Figma token in plaintext into a project-root .env file that may later be committed or shared, a local secret-hygiene weakness the user is prompted about.

FIGMA_ACCESS_TOKEN=${token}
vector:code
Reviewer's reasoning

The token is written to a local .env only after the user chooses to save it, so this is a local secret-hygiene weakness the user decides on.

Credential access

mediumNoteConfirmed on reviewhigh confidence

The server.json launch config declares an optional secret FIGMA_ACCESS_TOKEN for the Figma API it wraps, which is a note; the top-level 'No API keys.' description understates this optional token, a claim misstatement at note level.

"name": "FIGMA_ACCESS_TOKEN"
vector:metadata
Reviewer's reasoning

The optional Figma token is declared as a secret for the Figma API the server wraps and is user-supplied; the 'No API keys' misstatement is a note-level false claim.

Tool poisoning

mediumNoteConfirmed on reviewlow confidence

The compare tool description suggests the agent obtain the design image from a connected Figma MCP server's screenshot tool, routing input through another tool; a cross-tool suggestion for the tool's own input, noted only.

if a Figma MCP server is connected, export the frame
vector:metadata
Reviewer's reasoning

The compare description suggests exporting the design frame through a Figma MCP screenshot tool the user has connected. This is a cross-tool input suggestion within the declared purpose of comparing a design image, with no deception, no hidden instruction, and no change to how another tool behaves, so it is a note.

Credential access

mediumNoteConfirmed on reviewmedium confidence

The compare tool's authState parameter reads a caller-named Playwright storageState file (cookies and localStorage) to screenshot authenticated views, a declared core capability, so it is a note.

Path to a Playwright storageState JSON file (cookies + localStorage).
vector:metadata
Reviewer's reasoning

The authState parameter reads a Playwright storageState file that the caller names, to screenshot authenticated views. This is a documented core capability whose path the user supplies, and the cited text shows no exfiltration to an undisclosed destination, so it is a note.

Supply chain

lowNoteConfirmed on reviewhigh confidence

The desktop package runs electron-rebuild at install time to rebuild node-pty for Electron; this is the publisher's own native-module build step and is disclosed in package.json, so it is a note.

"postinstall": "electron-rebuild -f -w node-pty"
vector:metadata
Reviewer's reasoning

The electron-rebuild postinstall is the publisher's own native-module build step, declared in package.json; it runs only as part of installing the publisher's package, which is a note.

Supply chain

lowNoteConfirmed on reviewmedium confidence

The desktop devDependency @kiyas/core is unpinned at '*', an unpinned version of what appears to be the publisher's own package, which is a note.

"@kiyas/core": "*"
vector:metadata
Reviewer's reasoning

An unpinned devDependency on the publisher's own @kiyas/core is a hygiene issue for the publisher's build and is not a consumer-facing harm.

Privilege escalation

lowNoteConfirmed on reviewmedium confidence

The Electron main window disables the renderer sandbox while exposing a preload bridge, a weak default hardening choice noted for the installer.

sandbox: false
vector:code
Reviewer's reasoning

sandbox: false is a weak hardening default in the publisher's own app window, a note with no attacker-independent action by the artifact.

Supply chain

lowNoteConfirmed on reviewlow confidence

The lockfile records the electron/node-gyp dependency as a git source pinned to a commit on github.com (electron's official repository) rather than a registry tarball; this is a dependency record that is pinned and from an official host, so it is a note only.

git+ssh://git@github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2
vector:metadata
Reviewer's reasoning

The lockfile entry is a dev-only dependency record pinned to a commit on electron's official GitHub repository, which the carve-out for lockfile resolution covers.

Supply chain

lowNoteConfirmed on reviewhigh confidence

The installer error text tells the user to install the third-party Claude Code CLI from the official npm registry; a disclosed install instruction the user chooses to run, so a note only.

npm install -g @anthropic-ai/claude-code
vector:instruction
Reviewer's reasoning

The error text names the official npm package and asks the user to run it, a disclosed install instruction the user chooses to follow.

Agent hijacking

lowNoteConfirmed on reviewlow confidence

The component resolver lets a Claude or Codex agent read and search repository files, then uses its unvalidated JSON output (url, selector) to drive screenshot capture, so repository content could steer the resolved target; this is an injection weakness, not a shipped instruction.

"Grep",
vector:instruction
Reviewer's reasoning

Repository content could only steer the resolver if an outside author placed it there, so the artifact merely makes the injection possible, which is a note.

Supply chain

lowNoteConfirmed on reviewmedium confidence

The CLI package declares an install-time postinstall script that runs on every npm install of the package; its contents are not shown, so it is noted for the install path.

scripts.postinstall: node scripts/postinstall.js
vector:code
Reviewer's reasoning

The postinstall hook runs on the user's own npm install, which is a user-invoked step. The script shown only prints a welcome message, so the install path is a note, not an overreach.

Supply chain

lowNoteConfirmed on reviewhigh confidence

The CLI package runs scripts/postinstall.js on npm install; the script only prints a welcome message, so the undeclared install hook is a note.

"postinstall": "node scripts/postinstall.js"
vector:code
Reviewer's reasoning

The postinstall script is declared in package.json and runs only on the user's npm install. Its served contents only print a message and change nothing else, so the install hook is a note.

Supply chain

lowNoteConfirmed on reviewmedium confidence

The CLI devDependency on the workspace package @kiyas/core is pinned to any version with '*', an unpinned reference that only the publisher's own build uses.

"@kiyas/core": "*"
vector:metadata
Reviewer's reasoning

An unpinned devDependency on the publisher's own @kiyas/core is used only in the publisher's build, a hygiene note.

Reconnaissance

infoNoteConfirmed on reviewlow confidence

The desktop app enumerates local listening ports to locate dev servers for the user's comparison target; this serves the declared task and is a note.

// dev servers live in the registered-port range; skip system + ephemeral
vector:code
Reviewer's reasoning

Port enumeration limited to dev-server runtimes serves the declared comparison-target task, which the code states as its purpose.

Open questions 1

What the analysis could not settle from the code alone.

Does loadReport in @kiyas/core confine reportId to the reports directory, so that the jsonPath or reportPath it returns cannot point at files outside it, which get_diff_report would then read and return inline?
Credential access