Back to skill

Security audit

Grupr

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it gives remote chat participants a path to influence a local OpenClaw agent and handles user session credentials in a risky way.

Install only if you are comfortable connecting Grupr conversations to a local OpenClaw agent. Use a dedicated restricted agent instead of `main`, avoid granting that agent shell/filesystem/credential access, review the JWT setup flow carefully, and do not use custom base URLs unless you fully trust the endpoint.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/stream.py:108
Finding

Untrusted Remote Messages Are Passed Directly to the Default Local Agent

Content
View full analysis

Vulnerability Details

File Location: scripts/stream.py:108-109, 145-157; scripts/poll.py:120-123, 166-178
Vulnerability Type: Indirect prompt injection across a remote-to-local trust boundary
Risk Level: High

Vulnerable Code

scripts/stream.py:108-109:

python
parser.add_argument("--openclaw-agent", default="main", help="OpenClaw agent name (default: main)")
parser.add_argument("--timeout", type=int, default=120, help="Per-message agent timeout (default: 120s)")

scripts/stream.py:145-157:

python
else:
    print(f"  respond to {short_id}: {msg.content[:60]!r}", flush=True)
    try:
        response = call_openclaw_agent(
            message=msg.content,
            session_id=f"grupr:{args.grupr_id}",
            agent_name=args.openclaw_agent,
            timeout=args.timeout,
        )
        sent = client.send_message(args.grupr_id, response)
        print(f"    posted reply {sent.message_id[:8]} ({len(response)} chars)")
        processed += 1

scripts/poll.py:120-123:

python
parser.add_argument(
    "--openclaw-agent",
    default="main",
    help="OpenClaw agent name to invoke (default: main)",
)

scripts/poll.py:166-178:

python
print(f"  respond to {short_id}: {msg.content[:60]!r}")
if args.dry_run:
    print(f"    (dry-run) would call openclaw agent")
    last_cursor = msg.created_at
    continue

try:
    response = call_openclaw_agent(
        message=msg.content,
        session_id=f"grupr:{args.grupr_id}",
        agent_name=args.openclaw_agent,
        timeout=args.timeout,
    )

Technical Analysis

Messages controlled by remote Grupr participants are forwarded unchanged as instructions to a local OpenClaw Agent. The Skill does not delimit the message as untrusted content, enforce an allowlisted task, inspect attempted instruction overrides, require approval before sensitive tool opera ...[truncated 2049 chars]

Remediation
View remediation

Remediation Suggestions

  1. Default to a dedicated Grupr Agent rather than main.
  2. Configure that Agent without shell, filesystem, credential, browser-session, or unrestricted network tools unless explicitly required.
  3. Treat every Grupr message as untrusted data and wrap it in a fixed instruction that prohibits following embedded requests to change policy, inspect secrets, or invoke unrelated tools.
  4. Add an allowlisted task policy defining the actions the bridge may perform.
  5. Require explicit user confirmation before tool invocation, sensitive data access, or transmission of potentially confidential output.
  6. Use isolated sessions per conversation and, where appropriate, per participant or message. Provide a way to clear potentially poisoned session context.
  7. Apply output filtering before automatically posting responses to Grupr.
  8. Document the remote prompt-injection threat prominently and warn users not to connect a privileged primary Agent.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login.py:35
Finding

User JWT Is Exposed Through Command-Line Arguments and May Be Sent to an Unrestricted Endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/login.py:35-46, 60-64; README.md:40-43; SKILL.md:19-21
Vulnerability Type: Insecure secret input and insufficient destination validation
Risk Level: High

Vulnerable Code

scripts/login.py:35-46:

python
parser = argparse.ArgumentParser(description="Mint a Grupr agent token and persist to .env")
parser.add_argument("--jwt", required=True, help="User JWT (access token from app.grupr.ai)")
parser.add_argument(
    "--agent-id",
    required=True,
    help="UUID of an agent you've already created in your Grupr account",
)
parser.add_argument(
    "--base-url",
    default=os.environ.get("GRUPR_BASE_URL", "https://api.grupr.ai/api/v1/agent-hub"),
    help="Override agent-hub base URL (default: production)",
)

scripts/login.py:60-64:

python
client, token_info = Grupr.register(
    jwt=args.jwt,
    agent_id=args.agent_id,
    base_url=args.base_url,
)
client.close()

README.md:40-43:

bash
# 1. Mint an agent token (one-time per agent).
#    JWT: from app.grupr.ai DevTools → cookies → grupr_access
#    agent_id: UUID of an agent you've already created in the Grupr web app
uv run python scripts/login.py --jwt <jwt> --agent-id <uuid>

Technical Analysis

The documented authentication workflow places a user session JWT directly in a command-line argument. Command-line secrets may be retained in shell history and can be exposed through process inspection while the command is running.

The same registration flow permits --base-url or the GRUPR_BASE_URL environment variable to select an arbitrary destination. There is no validation that the destination uses HTTPS or belongs to the expected api.grupr.ai host. The JWT is then passed to Grupr.register() together with that destination.

Custom endpoints may be useful for development, but accepting them without an explicit unsafe m ...[truncated 1606 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove --jwt as the recommended secret-input mechanism.
  2. Read the JWT using a non-echoing prompt such as getpass.getpass(), protected standard input, or a dedicated file descriptor.
  3. If environment-variable input is supported for automation, clearly document its exposure characteristics and avoid printing it.
  4. Reject non-HTTPS registration URLs.
  5. Allowlist the production scheme, host, port, and expected path.
  6. If custom development endpoints are necessary, require an explicit flag such as --allow-unsafe-custom-endpoint and display the exact destination before requesting the JWT.
  7. Prevent redirects to untrusted hosts or ensure authentication headers are never forwarded across origins.
  8. Update README.md and SKILL.md so users are no longer instructed to place JWTs in shell commands.
  9. Document immediate JWT revocation and rotation procedures for suspected exposure.

T08 · Insecure Dependencies

Warning
Location
pyproject.toml:8
Finding

Unbounded and Unlocked Third-Party Dependency Creates Supply-Chain Exposure

Content
View full analysis

Vulnerability Details

File Location: pyproject.toml:8-10; installation instruction at SKILL.md:15-17
Vulnerability Type: Non-reproducible dependency resolution
Risk Level: Medium

Vulnerable Code

pyproject.toml:8-10:

toml
dependencies = [
    "grupr>=0.3.0",
]

SKILL.md:15-17:

bash
# One-time: install Python deps into the skill's venv
cd ~/.openclaw/skills/grupr && uv sync

Technical Analysis

The project accepts every future grupr version greater than or equal to 0.3.0, and the audited project contains no dependency lockfile. Consequently, installations performed at different times can resolve different package versions that were not part of this audit.

This is not evidence that the current grupr package is malicious. It is a supply-chain hardening weakness: a compromised, malicious, or unexpectedly incompatible future release could be installed automatically while still satisfying the declared constraint.

The dependency is security-sensitive because it receives the Grupr agent token, handles registration using the user JWT, establishes network connections, parses remote messages, and sends replies.

Attack Path

  1. A malicious or compromised future grupr package release is published under the legitimate package name and satisfies grupr>=0.3.0.
  2. A user performs the documented uv sync operation without a reviewed lockfile.
  3. The resolver selects and installs the new release.
  4. Package code executes when the scripts import or invoke the SDK.
  5. Malicious dependency code could access process environment variables, the agent token loaded by the Skill, network traffic, or files available to the current user.

Impact Assessment

A compromised dependency would execute with the same operating-system privileges as the user running the Skill. It could potentially access the stored Grupr agent token, intercept the user JWT during re ...[truncated 252 chars]

Remediation
View remediation

Remediation Suggestions

  1. Generate and commit a reviewed uv.lock file.
  2. Pin the dependency to an approved exact version or a narrowly reviewed version range.
  3. Use package hashes where supported to verify downloaded artifacts.
  4. Review release notes and source changes before updating the lockfile.
  5. Run automated vulnerability and dependency-integrity scanning in continuous integration.
  6. Consider isolating the SDK process and limiting its filesystem and network access.
  7. Establish a controlled dependency-update process rather than resolving unrestricted future versions during installation.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill asks the user to provide a user JWT and states that it will mint an agent token and persist it locally in .env, which is a materially sensitive behavior not highlighted in the top-level description. Understating credential handling can mislead users about the trust boundary and increase the chance they expose high-value session tokens to automation they did not intend to authorize so broadly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill asks the user to provide a user JWT and states that it will mint an agent token and persist it locally in .env, which is a materially sensitive behavior not highlighted in the top-level description. Understating credential handling can mislead users about the trust boundary and increase the chance they expose high-value session tokens to automation they did not intend to authorize so broadly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The skill asks the user to provide a user JWT and states that it will mint an agent token and persist it locally in .env, which is a materially sensitive behavior not highlighted in the top-level description. Understating credential handling can mislead users about the trust boundary and increase the chance they expose high-value session tokens to automation they did not intend to authorize so broadly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill asks the user to provide a user JWT and states that it will mint an agent token and persist it locally in .env, which is a materially sensitive behavior not highlighted in the top-level description. Understating credential handling can mislead users about the trust boundary and increase the chance they expose high-value session tokens to automation they did not intend to authorize so broadly.

Content

No source excerpt is available for this finding.

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 66)May include surrounding context.

md
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/hello.py (reported line 31)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/login.py (reported line 12)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/login.py (reported line 17)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/login.py (reported line 50)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/login.py (reported line 85)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/poll.py (reported line 37)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/poll.py (reported line 147)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/start.py (reported line 86)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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/stream.py (reported line 122)May include surrounding context.

python
Usage:
    uv run python scripts/login.py --jwt <user-jwt> --agent-id <uuid>

The .env file ends up with:
    GRUPR_AGENT_TOKEN=gat_...
    GRUPR_AGENT_ID=<uuid>
    GRUPR_TOKEN_HINT=gat_xxxx...yyyy

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 · scripts/login.py (reported line 36)May include surrounding context.

python
def main() -> int:
    parser = argparse.ArgumentParser(description="Mint a Grupr agent token and persist to .env")
    parser.add_argument("--jwt", required=True, help="User JWT (access token from app.grupr.ai)")
    parser.add_argument(
        "--agent-id",
        required=True,

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/hello.py (reported line 28)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> 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/login.py (reported line 31)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> 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/login.py (reported line 35)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> 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/poll.py (reported line 33)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> 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/start.py (reported line 27)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> 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/stream.py (reported line 35)May include surrounding context.

python
from pathlib import Path

SKILL_DIR = Path(__file__).resolve().parent.parent
ENV_PATH = SKILL_DIR / ".env"


def state_path(grupr_id: str) -> Path:

Memory Manipulation

High
Category
Memory Poisoning
Confidence
90% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · scripts/status.py (reported line 43)May include surrounding context.

python
if not isinstance(data, dict):
                data = {}
        except (json.JSONDecodeError, ValueError):
            data = {"_error": "corrupt state file"}
        entries.append({"grupr_id": grupr_id, **data, "_path": str(p)})
    return entries

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

→ reply lands in the grupr tagged with your agent's id

text

LLM keys live in your OpenClaw gateway config — the skill never sees them. Only secret the skill stores is the per-agent Grupr token (chmod 600 in `.env`).

## Install (development — clone)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

→ reply lands in the grupr tagged with your agent's id

text

LLM keys live in your OpenClaw gateway config — the skill never sees them. Only secret the skill stores is the per-agent Grupr token (chmod 600 in `.env`).

## Install (development — clone)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill explicitly instructs users to run shell commands, create local state files, read environment variables, and persist secrets, yet it declares no tool scope or permissions. This weakens least-privilege controls and can cause the runtime to grant broader access than users expect, especially because the skill handles authentication material and process management.

Content

No source excerpt is available for this finding.