Back to skill

Security audit

Dirigera Control (IKEA smart home)

Security checks for vulnerabilities and agentic risk

Overview

This skill is for IKEA smart-home control, but it handles hub tokens and broad device shutdown actions in ways that deserve careful review before installation.

Install only if you are comfortable giving an agent control over IKEA Dirigera devices. Treat the token as a smart-home credential, avoid saving it in shared or synced folders, prefer a protected secret store, and require explicit confirmation before outlet, scene, or whole-home actions. Be especially cautious using token generation on untrusted networks because the script disables TLS certificate checks.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:13
Finding
Unpinned Third-Party Dependency Creates a Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 13-15 **Vulnerability Type**: Unpinned third-party package installation **Risk Level**: Medium ### Vulnerable Code ```python pip install dirigera ``` ### Technical Analysis The installation instructions retrieve and execute the current version of the `dirigera` package without a version constraint, lock file, package hash, or documented integrity verification. Consequently, the reviewed Skill does not fully determine the code that will execute after users follow its prerequisites. This is a supply-chain weakness rather than evidence that the current `dirigera` package is malicious. However, a compromised package release, unauthorized maintainer action, or incompatible future version could execute arbitrary code during installation or import. The dependency operates in the same security context as the Skill and may receive the Dirigera hub address and access token. ### Attack Path 1. An attacker compromises the upstream package, publishing account, or package distribution channel. 2. A malicious or altered release becomes the version selected by `pip install dirigera`. 3. A user or agent follows the Skill instructions and installs the unpinned package. 4. Installation-time or import-time code executes with the user's privileges. 5. The compromised dependency can read accessible files and environment data, intercept the hub token, issue smart-home commands, or alter local application behavior. ### Impact Assessment Successful exploitation could provide code execution with the privileges of the user installing or running the Skill. The resulting scope may include: - Reading the plaintext Dirigera token and other user-accessible files. - Controlling smart-home devices through the hub. - Accessing environment variables and local network resources. - Modifying user-owned files or application behavior. The vulnerability does not independently grant administrative privileges; its maximum ...[truncated 59 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `dirigera` to a specifically reviewed version: ```text dirigera==<reviewed-version> ``` 2. Maintain a lock file that records all transitive dependency versions. 3. Require package hashes, such as through `pip install --require-hashes -r requirements.txt`. 4. Document the expected package index and prohibit untrusted alternative indexes. 5. Review dependency updates before changing the pinned version. 6. Run the Skill in a least-privileged environment without access to unrelated secrets or files. 7. Do not allow an agent to install or upgrade dependencies automatically without explicit user authorization. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_token_wrapper.py:17
Finding
OAuth Token Generation Disables TLS Certificate Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_token_wrapper.py`, lines 17-21 and 60-92 **Vulnerability Type**: Disabled TLS certificate validation during a sensitive authentication flow **Risk Level**: High ### Vulnerable Code ```python try: import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) except ImportError: print("Error: requests library not found. Install with: pip install requests") sys.exit(1) ``` ```python try: response = requests.get(auth_url, params=params, verify=False, timeout=10) response.raise_for_status() auth_code = response.json()["code"] print(f"✓ Authorization code received") except Exception as e: print(f"✗ Failed to get authorization code: {e}") return None # Step 2: Wait for button press and get token print(f"\nWaiting for button press on Dirigera hub at {ip_address}...") print(f"Timeout: {timeout} seconds") print() token_url = f"https://{ip_address}:8443/v1/oauth/token" data = ( f"code={auth_code}" f"&name={socket.gethostname()}" f"&grant_type=authorization_code" f"&code_verifier={code_verifier}" ) headers = {"Content-Type": "application/x-www-form-urlencoded"} start_time = time.time() attempt = 0 while time.time() - start_time < timeout: attempt += 1 try: response = requests.post( token_url, headers=headers, data=data, verify=False, timeout=5 ) ``` ### Technical Analysis Both HTTPS requests in the OAuth flow use `verify=False`, causing the client to accept any server certificate. The code also globally suppresses `InsecureRequestWarning`, removing the runtime indication that authentication data is being transmitted without server identity verification. Although the connection uses HTTPS encryption, encryption without authenticated server identity does not prot ...[truncated 2180 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove both `verify=False` arguments and stop globally suppressing TLS warnings. 2. Establish trust in the hub certificate using one of the following: - A vendor-supported certificate authority. - A user-supplied trusted certificate. - Certificate or public-key fingerprint pinning. - An explicit trust-on-first-use workflow that displays and records the fingerprint after user verification. 3. Fail closed when certificate validation or fingerprint verification fails. 4. Avoid sending the machine hostname by default. Use a neutral client name such as `dirigera-control`, or expose an explicit `--client-name` option. 5. Encode request data through a dictionary passed to `requests`, rather than manually constructing the form body: ```python data = { "code": auth_code, "name": client_name, "grant_type": "authorization_code", "code_verifier": code_verifier, } ``` 6. Add tests confirming that an untrusted certificate is rejected. 7. Document the hub-certificate enrollment and rotation process so users can distinguish legitimate certificate changes from interception. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_token_wrapper.py:138
Finding
Dirigera Access Token Is Written to a Predictable Plaintext File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_token_wrapper.py`, lines 138-142 and 158-164 **Vulnerability Type**: Insecure storage of a sensitive access token **Risk Level**: High ### Vulnerable Code ```python parser.add_argument( "--output", default="dirigera_token.txt", help="Output file path (default: dirigera_token.txt in current directory)", ) ``` ```python # Save to file output_path.write_text(token + "\n") print(f"\n✓ Token saved to: {output_path.absolute()}") print(f"\nTo use this token:") print(f' In Python: token = Path("{output_path}").read_text().strip()') ``` The documented workflow reinforces plaintext storage: ```python from pathlib import Path token = Path("dirigera_token.txt").read_text().strip() ``` ```bash TOKEN=$(cat /path/to/token.txt) ``` ### Technical Analysis The generated hub access token is stored in a predictable plaintext file in the current working directory by default. `Path.write_text()` uses the process environment and default file-creation permissions; the code does not explicitly require mode `0600`, reject symbolic links, ensure exclusive creation, or verify that the destination is owned by the current user. If the destination already exists, it is overwritten. A local attacker able to prepare the output path may potentially use a symbolic link to redirect the write to another user-writable target. More commonly, the token may be exposed through permissive filesystem defaults, shared workspaces, backups, synchronization tools, accidental source-control commits, or later processes that can read the working directory. The printed absolute path also reveals the token's storage location to logs, though the token value itself is not printed. ### Attack Path 1. The user runs token generation without selecting a protected credential store. 2. The script writes the token to `dirigera_token.txt` or another specified path. 3. The file receives permissions derived from the current umask, ...[truncated 1282 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an operating-system credential store or dedicated secrets manager instead of a plaintext file. 2. If file storage is necessary, create the file atomically with owner-only permissions: ```python import os flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(output_path, flags, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as handle: handle.write(token + "\n") ``` 3. Reject symbolic links and unsafe existing files rather than silently overwriting them. 4. Verify that the parent directory is trusted and not writable by untrusted users. 5. Warn users when the selected output location is inside a source repository, shared directory, or synchronized folder. 6. Add `dirigera_token.txt` and equivalent token files to source-control ignore rules. 7. Document token revocation and rotation procedures. 8. Avoid recording the token-file location in broadly accessible logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/find_dirigera_ip.py:153
Finding
Access Token Can Be Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/find_dirigera_ip.py`, line 153 **Vulnerability Type**: Sensitive credential accepted directly as a process argument **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--token", help="Dirigera API token (optional)") ``` The documented invocation is: ```bash python scripts/find_dirigera_ip.py --token <dirigera-token> ``` ### Technical Analysis The discovery script accepts the Dirigera access token directly on the command line. Command-line arguments may be visible to other local users or monitoring software through process-inspection interfaces while the command is running. They may also be retained in shell history, terminal logs, command auditing systems, automation logs, or diagnostic output. The token is legitimately required when the user requests authenticated verification of candidate hubs. However, passing it through `argv` is not the minimum-exposure input mechanism. ### Attack Path 1. The user invokes the discovery script with `--token` and the actual access token. 2. The token appears in the process argument vector while the script scans candidate addresses. 3. A local user or monitoring process reads the command line from process-inspection facilities, or the shell records it in history. 4. The actor obtains the token from the process listing, history file, audit log, or terminal record. 5. The actor combines the token with the discovered or known hub IP. 6. The actor authenticates to the hub and performs operations allowed by the token. ### Impact Assessment An attacker who obtains the argument can acquire the same hub API privileges as the legitimate token holder. Depending on the Dirigera API authorization scope, this may include: - Enumerating devices and household room metadata. - Reading smart-home operational state. - Controlling lights and outlets. - Triggering scenes. - Observing reachability and battery information. Exploitation requires local a ...[truncated 143 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace direct token arguments with safer input mechanisms, such as: - Reading from an owner-only token file. - Reading from standard input without terminal echo. - Retrieving the token from an operating-system credential store. - Receiving it through an already-open protected file descriptor. 2. If backward compatibility requires `--token`, mark it as deprecated and display a warning about process-list and shell-history exposure. 3. Add an option such as `--token-file` and verify that the file is a regular file, is not a symbolic link, and has owner-only permissions. 4. Ensure errors and debug logs never include the token value. 5. Recommend deleting any shell-history entries that previously included the token and rotating a token if exposure is suspected. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code substantially matches the core smart-home control portion of the description: it initializes a Dirigera hub, controls lights and outlets, checks status, reports unreachable devices, and checks controller battery levels. However, the declared description includes several capabilities not present in this code chunk: scene control, API token generation, hub IP discovery, and Cloudflare tunnel/VPS accessibility. It also mentions adjusting color, but the code only supports color temperature, not general color selection. Because these are user-facing declared capabilities and access modes not implemented in the supplied code, this is a description/behavior mismatch, though the primary domain and most core functions do align.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs use of shell commands, local file reads/writes, and network interaction, but it declares no explicit tool scope or permission boundaries. In an agent environment, this can cause the skill to run with broader-than-necessary authority, increasing the chance of unintended network scanning, token handling, or filesystem access beyond what users expect.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The activation text is broad enough to match many generic smart-home requests, which can cause the agent to invoke this skill in situations the user did not specifically intend. Because the skill can control physical devices and initiate discovery/token workflows, over-triggering raises the risk of unauthorized or surprising actions in the user's environment.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill omits an upfront warning that its commands can immediately change real-world devices such as lights and outlets. In context, this is safety-relevant because users may not realize a natural-language request could trigger physical actions, leading to unintended device operation, nuisance, or disruption.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
These examples demonstrate bulk shutdown of all lights or all outlets without any embedded warning, confirmation step, or guidance about scope. In a smart-home control skill, such patterns normalize broad disruptive actions and could be reused by an agent in response to ambiguous prompts, causing unintended home-wide outages or interruption of connected appliances.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The energy-saving example turns off non-essential outlets and then all lights, but provides no warning that the classification of 'non-essential' is hard-coded and may be wrong in a real deployment. In this skill context, controlling physical devices through a hub makes the pattern more dangerous because an agent or user could apply it directly and shut down important equipment, creating safety, availability, or property risks.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _arp_ips() -> List[str]:
    """Best-effort ARP table parse."""
    try:
        result = subprocess.run(
            ["arp", "-a"],
            check=False,
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"\nTrying generate-token against {ip} ...")
        print("When prompted, press the action button on the Dirigera hub, then hit ENTER.")
        try:
            subprocess.run(
                ["generate-token", ip],
                check=False,
            )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
}

    try:
        response = requests.get(auth_url, params=params, verify=False, timeout=10)
        response.raise_for_status()
        auth_code = response.json()["code"]
        print(f"✓ Authorization code received")
Confidence
98% confidence
Finding
Disabling TLS certificate verification on the authorization request makes the script trust any certificate presented by the remote endpoint. An attacker on the network path or controlling DNS/routing could impersonate the hub, intercept the OAuth flow, and influence or capture sensitive authentication material.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
token_url,
                headers=headers,
                data=data,
                verify=False,
                timeout=5
            )
Confidence
98% confidence
Finding
Disabling TLS verification on the token exchange is especially dangerous because this request carries the authorization code and PKCE verifier and receives the access token. A man-in-the-middle could impersonate the hub and obtain enough material to redeem or return a fraudulent token, leading to unauthorized access to smart home devices.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script writes a long-lived access token directly to disk in plaintext without setting restrictive permissions or warning the operator that the file is sensitive. On multi-user systems, shared directories, backups, or accidental commits, this can expose the token and allow unauthorized control of the smart home hub.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The helper functions expose home-wide destructive actions such as turning off all lights or all outlets with no confirmation, scoping restrictions, safeguard checks, or high-risk labeling. In a smart-home control skill, these methods can be invoked by higher-level agent logic from ambiguous, mistaken, or maliciously induced requests, causing broad disruption to the user’s environment and potentially powering off safety- or availability-relevant devices connected to smart outlets.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The documentation presents state-changing light and outlet control methods without explicitly warning that these commands will immediately affect physical devices. In a smart-home control skill, this can contribute to unsafe or unintended actuation if downstream agents or users treat the examples as harmless read-only operations.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The scene documentation describes `scene.trigger()` without warning that a scene can execute multiple device actions at once. In this skill context, scene activation may affect numerous lights, outlets, or automations simultaneously, increasing the risk of unintended physical changes beyond what a user expects from a single command.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The script uses the literal room name "Køkken" in its example call, which bakes in a locale-specific assumption. For a general-purpose example file, this can conflict with language/locale neutrality expectations because no opt-in or justification is provided.

Static analysis

No suspicious patterns detected.