T09 · Insecure Skill Coding Practices
- Location
scripts/jettyd-cli.js:14- Finding
Unrestricted API Base URL Can Redirect Bearer Credentials to an Attacker-Controlled Server
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent IoT control integration, but it gives agents live device-control and credential-bearing network authority with weak safety and endpoint scoping.
Install only if you are comfortable giving an agent API-key access to real IoT devices. Use narrowly scoped tokens, keep secrets out of repositories and firmware defaults, pin optional MCP/Python dependencies, avoid custom base URLs unless you fully trust them, and require human confirmation before relay, actuator, config, or webhook changes.
scripts/jettyd-cli.js:14Unrestricted API Base URL Can Redirect Bearer Credentials to an Attacker-Controlled Server
blueprint.md:95Unpinned Runtime and Installation Dependencies Create Supply-Chain Execution Risk
examples/langchain_tool.py:107Runnable LangChain Demo Can Issue a Physical Device Command Without Explicit Confirmation
The skill description understates several impactful capabilities: webhook creation/listing, telemetry retrieval, and especially pushing full device configuration rather than narrowly scoped rules. Underdeclared capabilities reduce informed consent and can cause users or orchestrators to authorize broader actions than they intended on IoT infrastructure.
The skill description understates several impactful capabilities: webhook creation/listing, telemetry retrieval, and especially pushing full device configuration rather than narrowly scoped rules. Underdeclared capabilities reduce informed consent and can cause users or orchestrators to authorize broader actions than they intended on IoT infrastructure.
Referenced artifact was not completely inspected
All operations go through `scripts/jettyd-cli.js`.
Without declared permissions the skill's intent is opaque and cannot be validated.
The skill provides commands that can change device state (command), deploy automations (push_config), and create outbound integrations (create_webhook) without any documented user warning or confirmation guidance. In an IoT context, silent state changes can trigger physical actions, persistent automations, or external data flows, making accidental misuse materially more dangerous.
The skill explicitly enables physical-world actions such as turning on irrigation relays and managing device rules, but it provides no visible warning that commands may affect real hardware. In an agent context, missing safety guidance increases the chance of unintended actuation, equipment damage, or unsafe environmental changes caused by user misunderstanding or autonomous tool use.
The documentation tells users to handle API keys, fleet tokens, Wi-Fi SSIDs/passwords, and webhook endpoints, but it does not warn about secure secret storage or exposure risks. In practice, readers may hardcode secrets, commit them to source control, or paste them into logs/configs that an agent or other local tools can access.
The blueprint instructs users to place a fleet token into sdkconfig.defaults, a file that is commonly stored alongside source and can easily be committed, reused across builds, or extracted from development environments. Long-lived embedded or build-time tokens increase the risk of persistent unauthorized device enrollment or platform access if the file, firmware artifacts, or repository contents are exposed.
1. Sign up at [jettyd.com](https://jettyd.com) → free tier (5 devices)
2. Get your API key from `api.jettyd.com/v1/api-keys`
3. Create a fleet token at `api.jettyd.com/v1/fleet-tokens`
4. Put the fleet token in `sdkconfig.defaults` (step 1 above)
**Test it:**
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Test it:
curl https://api.jettyd.com/v1/devices \
-H "Authorization: Bearer YOUR_API_KEY"
# → [{"id": "...", "name": "device-abc", "status": "online"}]
This example performs remote over-the-air configuration changes to a physical device, including rule deployment, using a bearer token. In the context of an AI-agent skill controlling hardware, such write operations are materially risky if invoked without explicit warnings, confirmation, authorization scoping, or rollback guidance, because they can alter real-world behavior persistently.
Push rules to your device over the air — no reflashing:
curl -X PUT https://api.jettyd.com/v1/devices/DEVICE_ID/config \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
The webhook example forwards device alerts to arbitrary external endpoints, which can leak device metadata, operational events, or sensitive alert content outside the platform. While webhook support is a legitimate feature, the absence of warnings about destination trust, secret handling, and data minimization makes this a real security concern in documentation aimed at agent-driven automation.
Subscribe a webhook to forward alerts to Slack, email, or anywhere:
curl -X POST https://api.jettyd.com/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
The blueprint instructs users to run an MCP server via npx @jettyd/mcp without pinning a specific version or integrity-verified package source. Because this package is meant to bridge an AI agent to real IoT devices, a compromised upstream package or unexpected breaking update could execute arbitrary code locally and gain access to API keys and device-control capabilities.
The send_command tool allows direct execution of device actions without any confirmation, authorization gating, allowlist enforcement, or safety interlock. In an IoT context, an LLM can misinterpret user intent, be socially engineered via prompt injection, or act on unsafe instructions, resulting in unauthorized or harmful changes to physical device state.
The agent’s system prompt frames the tools as being for answering questions about devices and sensor readings, but the available toolset also includes a state-changing command interface. This mismatch can cause an LLM agent to invoke a powerful actuation tool in contexts where the user expects read-only behavior, increasing the risk of unintended device manipulation through ambiguous or prompt-injected requests.
This markdown file lists operations that can send device commands, push device configuration, create fleet tokens, and delete webhooks, but it provides no warning that these actions can change device behavior or system configuration. For markdown files, safety-impacting behaviors should be accompanied by user-facing cautions about data, privacy, or system integrity implications.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
function getConfig() {
let apiKey = process.env.JETTYD_API_KEY;
let baseUrl = process.env.JETTYD_BASE_URL || 'https://api.jettyd.com/v1';
if (!apiKey) {
const cfgPath = join(homedir(), '.openclaw', 'openclaw.json');
The command subcommand performs a POST to /devices/{id}/commands, which can trigger actions on a physical or remote device. The code prints success only after the command is sent, but provides no prior confirmation prompt or explicit warning that this operation may affect device behavior.
The push_config subcommand sends configuration data with a PUT request to /devices/{id}/config, which can alter device behavior and may be difficult to undo. Although the script logs success afterward, there is no advance disclosure or confirmation before applying the change.
The stated skill purpose is to interact with IoT devices by reading sensors, sending commands, managing rules, and listing devices. The code additionally lists and creates account-level webhooks, which is a distinct integration-management capability not mentioned in the manifest description.
Detected: suspicious.env_credential_access