Skill Trust Decision

wip-xai-grok

Skill executes undeclared shell commands via 1Password CLI to resolve credentials without declaring shell:WRITE permission in SKILL.md, creating a doc-to-code mismatch on the most sensitive operation.

Install decision first Source: Manual upload Scanned: Apr 4, 2026
Files 10
Artifacts 10
Violations 2
Findings 4
Most direct threat evidence
High Priv Escalation
Undeclared shell:WRITE via 1Password CLI execSync

The resolveApiKey() function uses Node.js execSync to execute 'op read "op://Agent Secrets/X API/api key"', which is a shell command. This provides shell:WRITE capability but is not declared anywhere in SKILL.md's capabilities, metadata.dependencies, or allowed-tools mapping. The SKILL.md metadata shows dependencies: [] but the code has an implicit dependency on the 1Password CLI binary (op). While the README.md mentions this, SKILL.md is the canonical capability declaration and is silent on this.

core.mjs:28

Why this conclusion was reached

2/4 dimensions flagged
Block
Declared vs actual capability

2 undeclared or violating capabilities were inferred.

Review
Hidden execution and egress

10 lower-risk artifacts were extracted and still need context.

Block
Attack chain and severe findings

The report includes 0 attack-chain steps and 1 severe findings.

Review
Dependencies and supply chain hygiene

1 dependency or supply-chain issues need attention.

What drove the risk score up

Undeclared shell execution +25

core.mjs:28 uses execSync to call 'op read' CLI (1Password) for credential resolution. This is shell:WRITE access not declared in SKILL.md capabilities or metadata.dependencies

Credential access via CLI subprocess +15

The 1Password CLI integration reads secrets from a password manager, but the execSync call itself is undeclared shell access that could be swapped for arbitrary commands

SKILL.md declares zero dependencies but code uses exec +10

SKILL.md metadata shows 'dependencies: []' yet core.mjs imports node:child_process for shell execution

Local file read for image editing undeclared +5

edit_image() silently reads local files and base64-encodes them (core.mjs:252-258). SKILL.md describes image editing as URL-only without mentioning local filesystem access

Most important evidence

High Priv Escalation

Undeclared shell:WRITE via 1Password CLI execSync

The resolveApiKey() function uses Node.js execSync to execute 'op read "op://Agent Secrets/X API/api key"', which is a shell command. This provides shell:WRITE capability but is not declared anywhere in SKILL.md's capabilities, metadata.dependencies, or allowed-tools mapping. The SKILL.md metadata shows dependencies: [] but the code has an implicit dependency on the 1Password CLI binary (op). While the README.md mentions this, SKILL.md is the canonical capability declaration and is silent on this.

core.mjs:28
Declare the 1Password CLI dependency in SKILL.md metadata.dependencies or switch to environment-variable-only credential resolution. If 1Password is intentional, document it explicitly as a required binary dependency.
Medium Doc Mismatch

SKILL.md declares zero dependencies but code requires 1Password CLI

SKILL.md metadata shows 'dependencies: []' and the skill is described as requiring only XAI_API_KEY. However, the implementation silently requires the 'op' (1Password CLI) binary to be installed. The 1Password path 'op://Agent Secrets/X API/api key' is hardcoded with no fallback notice to the user. If 1Password is unavailable and XAI_API_KEY is not set, the error message is opaque.

SKILL.md:12
Update metadata.dependencies to include 'op (1Password CLI)' if the 1Password integration is intentional, or remove the execSync entirely and rely only on environment variable resolution.
Medium Sensitive Access

Silent local filesystem read in edit_image undeclared in docs

edit_image() accepts image file paths (not just URLs) and silently reads them from disk using readFileSync, base64-encodes them, and sends to the xAI API (core.mjs:252-258). SKILL.md describes edit_image as requiring a 'URL or base64 data URI' but never mentions that local file paths are also silently accepted and read. The function has filesystem:READ access that is neither declared in capabilities nor documented in the function description.

core.mjs:252
Document in SKILL.md that edit_image accepts local file paths as images, not just URLs. Declare filesystem:READ in the capability map for this skill.
Low Doc Mismatch

process.env cached with the actual API key value

resolveApiKey() caches the retrieved 1Password secret into process.env.XAI_API_KEY (core.mjs:33), meaning subsequent calls won't need the execSync but the key will live in the environment. This is a minor info-leak risk if the process memory is exposed.

core.mjs:33
Be aware that caching API keys in process.env makes them accessible via inspection of the process environment. This is standard practice but worth noting.

Declared capability vs actual capability

Network Pass
Declared READ
Inferred READ
core.mjs - all functions call https://api.x.ai/* for legitimate xAI API access
Shell Block
Declared NONE
Inferred WRITE
core.mjs:28 - execSync('op read "op://Agent Secrets/X API/api key"')
Filesystem Block
Declared NONE
Inferred READ
core.mjs:252-258 - edit_image reads local file paths and base64-encodes them
Environment Pass
Declared NONE
Inferred READ
core.mjs:25 - reads XAI_API_KEY from process.env
Skill Invoke Pass
Declared NONE
Inferred NONE
No self-invocation detected

Suspicious artifacts and egress

Medium External URL
https://console.x.ai/

README.md:29

Medium External URL
https://clawhub.ai/castanley/grok

README.md:122

Medium External URL
https://clawhub.ai

README.md:122

Medium External URL
https://api.x.ai/v1

SKILL.md:8

Medium External URL
https://docs.x.ai/developers/tools/web-search

SKILL.md:141

Medium External URL
https://docs.x.ai/developers/tools/x-search

SKILL.md:142

Medium External URL
https://docs.x.ai/docs/guides/image-generations

SKILL.md:143

Medium External URL
https://docs.x.ai/docs/guides/video-generations

SKILL.md:144

Medium External URL
https://opencollective.com/express

package-lock.json:137

Medium External URL
https://opencollective.com/fastify

package-lock.json:448

Dependencies and supply chain

PackageVersionSourceKnown vulnNotes
@modelcontextprotocol/sdk ^1.27.1 npm No Version loosely pinned with caret. Contains no known vulnerabilities at this version.
op (1Password CLI) any system binary No Not declared in package.json or SKILL.md. Implicit runtime dependency for credential resolution.

File composition

10 files · 2243 lines
JSON 2 files · 1183 linesJavaScript 3 files · 733 linesMarkdown 5 files · 327 lines
Files of concern · 4
package-lock.json JSON · 1142 lines
https://opencollective.com/express · https://opencollective.com/fastify
core.mjs JavaScript · 389 lines
Undeclared shell:WRITE via 1Password CLI execSync · Silent local filesystem read in edit_image undeclared in docs · process.env cached with the actual API key value
SKILL.md Markdown · 144 lines
SKILL.md declares zero dependencies but code requires 1Password CLI · https://api.x.ai/v1 · https://docs.x.ai/developers/tools/web-search · https://docs.x.ai/developers/tools/x-search · https://docs.x.ai/docs/guides/image-generations · https://docs.x.ai/docs/guides/video-generations
README.md Markdown · 130 lines
https://console.x.ai/ · https://clawhub.ai/castanley/grok · https://clawhub.ai
Other files · cli.mjs · mcp-server.mjs · CHANGELOG.md · package.json · RELEASE-NOTES-v1-0-3.md · PUNCHLIST.md

Security positives

All network requests go to legitimate, declared xAI API endpoints (api.x.ai) only
No obfuscation detected — no base64 eval, no dynamic code generation, no anti-analysis patterns
No credential exfiltration — the 1Password read is only used locally to obtain the API key for xAI
No remote code execution or reverse shell patterns present
No access to sensitive paths like ~/.ssh, ~/.aws, or .env files beyond the declared XAI_API_KEY
No hidden instructions in HTML comments or documentation
Package.json has version-pinned dependencies (except SDK peer deps resolved by host)
Input validation present (max limits on domains, handles, image count, etc.)
No data exfiltration — all API calls are to the legitimate xAI service
No supply-chain concerns — @modelcontextprotocol/sdk is a well-known, widely-used package