Back to skill

Security audit

Friends DB

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its friends-database purpose, but its calendar sync reads sensitive account configuration and passes the full environment to an external command, which needs review before use.

Install only if you want this skill to maintain a persistent private friends CRM and to import Google Calendar history through gog. Before using sync-calendar, make sure you trust the gog executable on PATH and understand that calendar attendee emails, titles, descriptions, locations, and account configuration may be processed. Avoid --replace-with-stub unless you have verified the backup and are ready for the SQLite database to become the source of truth.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/friends_db.py:648
Finding

External Calendar CLI Inherits the Complete Process Environment

Content
View full analysis

Vulnerability Details

File Location: scripts/friends_db.py, lines 648–666
Vulnerability Type: Excessive credential exposure to an external subprocess
Risk Level: Medium

Vulnerable Code

python
def load_gog_env() -> dict[str, str]:
    env = os.environ.copy()
    config_path = Path.home() / ".openclaw" / "openclaw.json"
    if config_path.exists():
        try:
            config = json.loads(config_path.read_text())
            gog_env = config.get("skills", {}).get("entries", {}).get("gog", {}).get("env", {})
        except json.JSONDecodeError:
            gog_env = {}
        for key, value in gog_env.items():
            env.setdefault(key, str(value))
    return env


def run_gog_json(args: list[str]) -> Any:
    env = load_gog_env()
    cmd = ["gog", *args, "--json", "--results-only", "--no-input"]
    try:
        result = subprocess.run(cmd, check=True, capture_output=True, text=True, env=env)

Technical Analysis

Calendar synchronization legitimately requires an authenticated external service, and the implementation invokes gog without shell=True, so command arguments are not interpreted by a shell. However, load_gog_env() copies every variable from the parent process and passes the resulting environment to an external executable. The environment may contain unrelated API keys, access tokens, cloud credentials, or other sensitive configuration that the calendar operation does not require.

The executable is also selected using the bare name gog, causing operating-system PATH resolution. Consequently, a PATH-shadowed, replaced, or compromised gog executable would receive both all inherited process secrets and the Skill-specific gog configuration loaded from ~/.openclaw/openclaw.json.

The reviewed source does not explicitly transmit these secrets and contains no attacker-controlled network destination. The weakness is the unnecessary exposure of credentials across the subprocess trust boundary.

Attac

...[truncated 1395 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace os.environ.copy() with a minimal allowlist containing only variables required to launch and authenticate gog, such as explicitly documented gog credential variables, a controlled PATH, and necessary locale settings.
  2. Resolve gog to an explicitly configured absolute path and verify that it points to a regular file owned by a trusted user and is not writable by untrusted users.
  3. Pin and document the trusted gog distribution source and version, and verify its checksum or signature during installation or deployment.
  4. Keep unrelated API keys and credentials out of the Skill process environment where possible.
  5. Validate that the env object loaded from ~/.openclaw/openclaw.json is a dictionary with an explicit set of permitted keys before passing values to the subprocess.
  6. Preserve the existing safe argument-array invocation and continue avoiding shell=True.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code accesses Google Calendar data through the gog CLI even though the skill is presented as a local private friends database helper. This broadens the data-access scope from local contact storage to external account data, creating a substantial privacy and consent issue if users invoke the skill expecting only local reads and writes.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/friends_db.py (reported line 649)May include surrounding context.

python
def load_gog_env() -> dict[str, str]:
    env = os.environ.copy()
    config_path = Path.home() / ".openclaw" / "openclaw.json"
    if config_path.exists():
        try:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill invokes shell commands and can read/write sensitive local files, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates an authorization ambiguity where an agent may execute broader capabilities than users expect, especially given this skill handles a private friends database and can modify workspace state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The migration command includes a destructive flag that replaces friends.md with a stub, but the skill does not present a clear warning or confirmation requirement before that action. This can lead to accidental data loss or unexpected alteration of the user's source file, particularly because the file contains personal contact information and may still be relied upon as a fallback record.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill metadata says it is for querying and maintaining a local friends database, but the implementation adds CRM automation and calendar-derived relationship tracking. This scope expansion matters because it processes more sensitive behavioral data than the manifest suggests, increasing privacy risk and surprising callers about what the skill actually does.

Content

No source excerpt is available for this finding.

Tainted flow: 'backup_path' from os.environ.get (line 331, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/friends_db.py (reported line 332)May include surrounding context.

python
ensure_private_dir(BACKUP_DIR)
    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_path = BACKUP_DIR / f"{path.stem}-{timestamp}{path.suffix}"
    shutil.copy2(path, backup_path)
    os.chmod(backup_path, 0o600)
    return backup_path

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill reads ~/.openclaw/openclaw.json and imports environment settings intended for another skill entry ('gog') to obtain external-service access indirectly. This is a privilege-boundary violation pattern: one skill should not silently inherit another skill's credentials/configuration to expand its own capabilities.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/friends_db.py (reported line 666)May include surrounding context.

python
env = load_gog_env()
    cmd = ["gog", *args, "--json", "--results-only", "--no-input"]
    try:
        result = subprocess.run(cmd, check=True, capture_output=True, text=True, env=env)
    except FileNotFoundError as exc:
        raise SystemExit("gog CLI not found; install it before syncing calendar") from exc
    except subprocess.CalledProcessError as exc:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The sync-calendar flow fetches calendar events using an external gog command and then processes attendee emails, event summaries, descriptions, and locations to match contacts. While the command help says it imports interactions from calendar history, the code lacks any explicit runtime disclosure, confirmation, or warning that sensitive calendar data will be accessed and sent through an external tool/account.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Migration mode can overwrite friends.md with a stub, which is more invasive than simply preferring the database over direct reads. That behavior can surprise users, alter source-of-truth expectations, and cause accidental data-management issues if invoked without fully understanding the side effect.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.