T09 · Insecure Skill Coding Practices
- Location
scripts/shopify-connector.mjs:189- Finding
Unvalidated Shop Host Can Receive Shopify OAuth Credentials
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its Shopify-connector purpose, but it handles powerful Shopify credentials and default permissions in ways users should review before installing.
Review this before installing on a real Shopify store. Start with read-only scopes, remove read_orders unless needed, protect the runtime directory and .env with owner-only permissions, validate the shop domain before OAuth exchange, add webhook size/rate limits, and require explicit confirmation for every product or content write.
scripts/shopify-connector.mjs:189Unvalidated Shop Host Can Receive Shopify OAuth Credentials
scripts/shopify-connector.mjs:79Shopify Secrets and Tokens Are Written Without Restrictive File Permissions
scripts/shopify-connector.mjs:349Unauthenticated Webhook Requests Are Buffered Without a Size Limit
scripts/setup-runtime.mjs:124Default OAuth Scopes Exceed the Connector's Implemented Requirements
scripts/shopify-connector.mjs:168OAuth State Is Neither Expired Nor Consumed After Successful Use
The skill description centers on Shopify/OpenClaw integration, but the detected behavior includes Tailscale inspection and callback exposure support that are not clearly reflected as primary capabilities in the declaration. This mismatch can mislead operators about what the skill will do on the host and network, making it easier for unexpected networking behavior or environment discovery to occur without informed approval.
Referenced artifact was not completely inspected
2. Use `scripts/setup-runtime.mjs guided-setup` to create the runtime directory, config files, `.env`, logs/state folders, and optional systemd unit template.
Referenced artifact was not completely inspected
2. Use `scripts/setup-runtime.mjs guided-setup` to create the runtime directory, config files, `.env`, logs/state folders, and optional systemd unit template.
Referenced artifact was not completely inspected
2. Use `scripts/setup-runtime.mjs guided-setup` to create the runtime directory, config files, `.env`, logs/state folders, and optional systemd unit template.
Referenced artifact was not completely inspected
2. Use `scripts/setup-runtime.mjs guided-setup` to create the runtime directory, config files, `.env`, logs/state folders, and optional systemd unit template.
Referenced artifact was not completely inspected
6. Use `scripts/shopify-connector.mjs` for auth URL generation, callback handling, webhook validation, and Shopify API calls.
Referenced artifact was not completely inspected
6. Use `scripts/shopify-connector.mjs` for auth URL generation, callback handling, webhook validation, and Shopify API calls.
Referenced artifact was not completely inspected
6. Use `scripts/shopify-connector.mjs` for auth URL generation, callback handling, webhook validation, and Shopify API calls.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
WorkingDirectory=%h/oc/shopify-runtime
Environment=SHOPIFY_RUNTIME_ROOT=%h/oc/shopify-runtime
Environment=SHOPIFY_CONFIG_PATH=%h/oc/shopify-runtime/config.json
Environment=SHOPIFY_ENV_PATH=%h/oc/shopify-runtime/.env
ExecStart=/usr/bin/env node %h/oc/shopify-runtime/shopify-connector.mjs run-server
Restart=always
RestartSec=3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## What it does
- generates Shopify OAuth install URLs
- exchanges OAuth callback codes for Shopify offline access tokens
- validates Shopify callback and webhook HMAC signatures
- runs a small local HTTP server for `/healthz`, OAuth callback handling, and webhook receipt
- performs explicit Shopify Admin GraphQL reads and user-confirmed writes
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.
- no browser automation
- no credential exfiltration or forwarding to third-party services
- no background tunneling binary, SOCKS proxy, VPN client, or reverse shell
- no self-update or self-modifying behavior
## Default exposure model
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.
- no browser automation
- no credential exfiltration or forwarding to third-party services
- no background tunneling binary, SOCKS proxy, VPN client, or reverse shell
- no self-update or self-modifying behavior
## Default exposure model
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
async function getSecret(flag, question, fallback = '') {
if (args[flag] !== undefined) return args[flag];
if (!prompter) return fallback;
return prompter.askSecret(question, fallback);
}
const tailscaleHostname = await getValue('tailscale-hostname', 'Tailscale/custom hostname for public HTTPS (omit https://, optional)', '');
This script stores Shopify client credentials and later OAuth access tokens in a plaintext .env file under a predictable path in the user's home directory. While local secret storage is expected for this skill, plaintext storage without explicit permission hardening increases the risk of credential disclosure to other local users, backup systems, or accidentally permissive filesystems.
ensureDir(path.join(runtimeRoot, 'logs'));
const configPath = path.join(runtimeRoot, 'config.json');
const envPath = path.join(runtimeRoot, '.env');
const connectorPath = path.join(runtimeRoot, 'shopify-connector.mjs');
const servicePath = path.join(runtimeRoot, 'shopify-connector.service');
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const stateDir = path.resolve(args['state-dir'] || process.env.SHOPIFY_STATE_DIR || path.join(runtimeRoot, 'state'));
const logsDir = path.resolve(args['logs-dir'] || process.env.SHOPIFY_LOGS_DIR || path.join(runtimeRoot, 'logs'));
const configPath = path.resolve(args.config || process.env.SHOPIFY_CONFIG_PATH || path.join(runtimeRoot, 'config.json'));
const envPath = path.resolve(args.env || process.env.SHOPIFY_ENV_PATH || path.join(runtimeRoot, '.env'));
const oauthStatePath = path.join(stateDir, 'oauth-state.json');
const installLogPath = path.join(logsDir, 'shopify-install.log');
const webhookLogPath = path.join(logsDir, 'shopify-webhooks.ndjson');
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const stateDir = path.resolve(args['state-dir'] || process.env.SHOPIFY_STATE_DIR || path.join(runtimeRoot, 'state'));
const logsDir = path.resolve(args['logs-dir'] || process.env.SHOPIFY_LOGS_DIR || path.join(runtimeRoot, 'logs'));
const configPath = path.resolve(args.config || process.env.SHOPIFY_CONFIG_PATH || path.join(runtimeRoot, 'config.json'));
const envPath = path.resolve(args.env || process.env.SHOPIFY_ENV_PATH || path.join(runtimeRoot, '.env'));
const oauthStatePath = path.join(stateDir, 'oauth-state.json');
const installLogPath = path.join(logsDir, 'shopify-install.log');
const webhookLogPath = path.join(logsDir, 'shopify-webhooks.ndjson');
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const stateDir = path.resolve(args['state-dir'] || process.env.SHOPIFY_STATE_DIR || path.join(runtimeRoot, 'state'));
const logsDir = path.resolve(args['logs-dir'] || process.env.SHOPIFY_LOGS_DIR || path.join(runtimeRoot, 'logs'));
const configPath = path.resolve(args.config || process.env.SHOPIFY_CONFIG_PATH || path.join(runtimeRoot, 'config.json'));
const envPath = path.resolve(args.env || process.env.SHOPIFY_ENV_PATH || path.join(runtimeRoot, '.env'));
const oauthStatePath = path.join(stateDir, 'oauth-state.json');
const installLogPath = path.join(logsDir, 'shopify-install.log');
const webhookLogPath = path.join(logsDir, 'shopify-webhooks.ndjson');
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const stateDir = path.resolve(args['state-dir'] || process.env.SHOPIFY_STATE_DIR || path.join(runtimeRoot, 'state'));
const logsDir = path.resolve(args['logs-dir'] || process.env.SHOPIFY_LOGS_DIR || path.join(runtimeRoot, 'logs'));
const configPath = path.resolve(args.config || process.env.SHOPIFY_CONFIG_PATH || path.join(runtimeRoot, 'config.json'));
const envPath = path.resolve(args.env || process.env.SHOPIFY_ENV_PATH || path.join(runtimeRoot, '.env'));
const oauthStatePath = path.join(stateDir, 'oauth-state.json');
const installLogPath = path.join(logsDir, 'shopify-install.log');
const webhookLogPath = path.join(logsDir, 'shopify-webhooks.ndjson');
Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal (+1 more)