Back to skill

Security audit

Lg Thinq Universal

Security checks for vulnerabilities and agentic risk

Overview

This LG ThinQ manager is coherent, but it needs review because it handles an account token, generated skills, shell commands, and persistent memory with incomplete safeguards.

Review before installing. Keep LG_PAT in a protected shell environment or secret manager rather than a root .env file, do not set LG_API_SERVER unless you fully trust the destination, inspect .api_server_cache before use, and avoid approving memory persistence unless the exact entry is shown and minimal. Treat generated device skills as code that can control real appliances.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lg_api_tool.py:90
Finding

LG Personal Access Token Can Be Sent to an Arbitrary API Server

Content
View full analysis
cache file > route API.""" if API_SERVER: return API_SERVER if os.path.exists(API_SERVER_CACHE): with open(API_SERVER_CACHE, "r") as f: server = f.read().strip() if server: return server ``` ```python def api_request(method, path, payload=None, snapshot=None): base_url = get_base_url() url = f"{base_url}{path}" headers = get_device_headers(snapshot) log_debug(f"API Request: {method} {url}") # Mask PAT in debug logs debug_headers = { k: (v if k != "Authorization" else "Bearer ***") for k, v in headers.items() } log_debug(f"Headers: {json.dumps(debug_headers)}") try: res = requests.request(method, url, headers=headers, json=payload, timeout=15) log_debug(f"API Response Status: {res.status_code}") return res.json() ``` From the generated control-script template in `scripts/generate_control_script.py`: ```python # API Server Priority: env var > .api_server_cache > default API_SERVER_CACHE = os.path.join(script_dir, ".api_server_cache") if os.getenv("LG_API_SERVER"): BASE_URL = os.getenv("LG_API_SERVER") elif os.path.exists(API_SERVER_CACHE): with open(API_SERVER_CACHE, "r") as f: BASE_URL = f.read().strip() else: BASE_URL = "https://api-kic.lgthinq.com" ``` ```python headers = {{ "Authorization": f"Bearer {{PAT}}", "x-api-key": API_KEY, "x-client-id": CLIENT_ID, "x-country": COUNTRY, "x-message-id": MESSAGE_ID, "Content-Type": "application/json", }} url = f"{{BASE_URL}}{{path}}" headers = get_headers(snapshot) try: res ...[truncated 2004 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/assemble_device_workspace.py:24
Finding

Shell Command Injection Through the Device Profile Path

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned Dependencies Are Installed from the Live Package Index

Content
View full analysis
=1.0.0 requests>=2.25.0 ``` From `setup.sh`: ```bash log_info "Synchronizing dependencies..." "$VENV_DIR/bin/pip" install -q -r "$REQUIREMENTS_FILE" log_info "Dependencies are up to date." ``` From `scripts/assemble_device_workspace.py`: ```python log("Linux/macOS detected. Creating virtual environment...") run_command("python3 -m venv venv", cwd=skill_path) log("Installing dependencies into venv...") run_command("./venv/bin/pip install -q -r requirements.txt", cwd=skill_path) ``` ### Technical Analysis Both dependencies use lower-bound-only constraints. Each setup or generated-Skill assembly resolves whatever future release currently satisfies those ranges. The downloaded artifacts are not pinned to reviewed versions and are not verified with cryptographic hashes. Installing dependencies from PyPI is disclosed and is functionally reasonable, but unrestricted future versions are not the minimum safe supply-chain privilege. A later compromised, malicious, or unexpectedly incompatible release can change the code executed in the Skill environment without any change to the audited repository. Assembly repeats this installation in every generated device Skill, increasing exposure and making environments diverge over time. ### Attack Path 1. A malicious or compromised release of an allowed dependency is published, or an upstream account/package distribution channel is compromised. 2. The user runs `setup.sh --confirm` or confirms device workspace assembly. 3. `pip` resolves the new release because it satisfies the broad `>=` constraint. 4. The package is downloaded and installed without hash verification. 5. Malicious package behavior executes during installation ...[truncated 446 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
SKILL.md:64
Finding

Mandatory Global Memory Persistence Can Poison Future Agent State

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/manual-setup.md:43
Finding

Documented Root Credential File Is Created Without Restrictive Permissions

Content
View full analysis
.env ``` From `references/manual-setup.md`: ```bash echo "LG_PAT=thinqpat_your_token_here" > .env echo "LG_COUNTRY=IN" >> .env ``` ```text > ⚠️ **SECURITY WARNING**: This `.env` file should ONLY exist in the universal manager root. NEVER copy your `LG_PAT` into generated per-device folders. Shell environment variables are always the safest option. ``` The same manual applies restrictive permissions only to the device-specific `.env`, which does not contain the PAT: ```bash echo "LG_DEVICE_ID=" > .env chmod 600 .env ``` ### Technical Analysis The documented fallback setup stores the LG PAT as plaintext in the manager's root `.env` file. Its effective permissions depend on the user's current umask. On systems with permissive defaults or shared group access, the file may be readable by other local users. The documentation recognizes that the PAT is sensitive and isolates it from generated device directories, but it does not apply the same `chmod 600` protection to the root file that actually contains the credential. Using a root `.env` fallback may be necessary for convenience, but creating it without enforced restrictive permissions exceeds minimum safe credential exposure. ### Attack Path 1. A user follows the README or manual fallback instructions to create the root `.env`. 2. The shell creates the file according to the current umask. 3. On a shared system with permissive permissions, another local account or process can read the file. 4. The attacker obtains the LG PAT. 5. The attacker uses the token against the LG ThinQ API within its granted scopes. A secondary exposure risk exists if users paste the literal token into an interactive shell where ...[truncated 439 chars]
Remediation
View remediation
.env chmod 600 .env ``` 2. Verify that `.env` is owned by the intended user and is a regular file rather than a symbolic link. 3. Add `.env` to version-control and backup exclusions. 4. Prefer a dedicated secret manager or protected process environment over a plaintext file. 5. Warn users that entering tokens directly in shell commands may retain them in shell history. 6. Have setup validate `.env` permissions and refuse or warn when group or world access is present. 7. Apply restrictive permissions to API route caches and other files containing device/account metadata as defense in depth. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (70)

Tainted flow: 'entry_point' from os.getenv (line 73, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/lg_api_tool.py (reported line 83)May include surrounding context.

python
log_debug(f"Calling Route API: {entry_point}")
    log_debug(f"Route Headers: {json.dumps(headers)}")

    res = requests.get(entry_point, headers=headers, timeout=10)
    data = res.json()
    log_debug(f"Route Response: {json.dumps(data)}")
    return data["response"]["apiServer"]

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 17)May include surrounding context.

text

### 2. Get Your Credentials
You can obtain your **Personal Access Token (PAT)** by following these steps:

1.  Visit the official portal: [https://connect-pat.lgthinq.com](https://connect-pat.lgthinq.com)
2.  Log in with your **ThinQ account**.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 36)May include surrounding context.

text

### 2. Get Your Credentials
You can obtain your **Personal Access Token (PAT)** by following these steps:

1.  Visit the official portal: [https://connect-pat.lgthinq.com](https://connect-pat.lgthinq.com)
2.  Log in with your **ThinQ account**.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/api-reference.md (reported line 24)May include surrounding context.

md
| Header | Required | Description |
|--------|----------|-------------|
| `Authorization` | Yes | `Bearer {LG_PAT}` - Personal Access Token |
| `x-api-key` | Yes | Fixed: `v6GFvkweNo7DK7yD3ylIZ9w52aKBU0eJ7wLXkSR3` |
| `x-client-id` | Yes | Fixed: `test-client-123456` |
| `x-country` | Yes | 2-letter ISO code (IN, US, GB, etc.) |

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 36)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 40)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 41)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/device-example.md (reported line 35)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/device-example.md (reported line 141)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/manual-setup.md (reported line 45)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/manual-setup.md (reported line 162)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/manual-setup.md (reported line 168)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/manual-setup.md (reported line 169)May include surrounding context.

md
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 196)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 268)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 271)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/generate_control_script.py (reported line 58)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/generate_control_script.py (reported line 64)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/generate_control_script.py (reported line 103)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/generate_control_script.py (reported line 272)May include surrounding context.

python
import os, sys, json, time, requests
from dotenv import load_dotenv

# Load .env from project root (where skill is installed)
script_dir = os.path.dirname(os.path.abspath(__file__))
env_path = os.path.join(script_dir, ".env")
if os.path.exists(env_path):

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

This section instructs storing LG_PAT in a .env file, which is plaintext credential storage. Even though it is intended for the project root rather than per-device folders, the token could still be exposed via local compromise, backups, accidental commits, or misplacement into a broader-access path.

Content

Scanner excerpt · references/manual-setup.md (reported line 42)May include surrounding context.

export LG_COUNTRY="IN"

text

**Or .env file in project root** (where this skill is installed):
```bash
echo "LG_PAT=thinqpat_your_token_here" > .env
echo "LG_COUNTRY=IN" >> .env

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

The line continues the pattern of directing users to persist LG_PAT and LG_COUNTRY in a .env file. Persisting an API token on disk increases the likelihood of credential theft and unintended reuse by other local processes or future automation.

Content

Scanner excerpt · references/manual-setup.md (reported line 44)May include surrounding context.

Or .env file in project root (where this skill is installed):

bash
echo "LG_PAT=thinqpat_your_token_here" > .env
echo "LG_COUNTRY=IN" >> .env

⚠️ SECURITY WARNING: This .env file should ONLY exist in the universal manager root. NEVER copy your LG_PAT into generated per-device folders. Shell environment variables are always the safest option.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The subprocess wrapper accepts free-form command strings and runs them through the shell. In this context, the script later interpolates paths and other values into command strings, so an attacker controlling those values can abuse the tool to execute arbitrary commands on the host.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 29)May include surrounding context.

python
def run_command(cmd, cwd=None, capture=False, env=None, exit_on_error=True):
    """Run a shell command safely."""
    try:
        result = subprocess.run(
            cmd, 
            cwd=cwd, 
            shell=True,

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

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.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 167)May include surrounding context.

python
parser = argparse.ArgumentParser(description="LG ThinQ Skill Factory")
    parser.add_argument("--id", required=True, help="Full Device ID")
    parser.add_argument("--location", help="Custom location name (e.g. livingroom)")
    parser.add_argument("--force", action="store_true", help="Overwrite existing skill")
    parser.add_argument("--confirm", action="store_true", help="Explicitly confirm all actions in the manifest")
    args = parser.parse_args()

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

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.

Content

Scanner excerpt · scripts/assemble_device_workspace.py (reported line 195)May include surrounding context.

python
print(f"The following actions will be performed for: {target_device.get('name')}")
        print(f"1. [FILE] Create directory: {skill_path}")
        print(f"2. [FILE] Write engine:    {skill_path}/lg_control.py")
        print(f"3. [FILE] Write SKILL:     {skill_path}/SKILL.md")
        print(f"4. [FILE] Write config:    {skill_path}/.env (Device ID isolation)")
        print(f"5. [FILE] Copy tools:      lg_api_tool.py, requirements.txt")
        print(f"6. [FILE] Copy references: public_api_constants.json, profile.json, .api_server_cache")

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/api-reference.md:99