Back to skill

Security audit

PinchBench

Security checks for vulnerabilities and agentic risk

Overview

PinchBench is a real benchmark skill, but it needs Review because it runs embedded grading code, can publish telemetry, deletes agent session history, and may install an unpinned external skill during a task.

Install only if you are comfortable running it in an isolated workspace with reviewed tasks. Use --no-upload for private runs, avoid setting PINCHBENCH_SERVER_URL unless you trust the endpoint, review any custom task automated checks as code, and expect benchmark agent session history for bench-* agents to be deleted.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib_grading.py:82
Finding

Arbitrary Code Execution Through Task-Embedded Grading Code

Content
View full analysis
GradeResult: grading_code = _extract_grading_code(task) if not grading_code: return GradeResult( task_id=task.task_id, score=0.0, max_score=1.0, grading_type="automated", breakdown={}, notes="No automated grading code found", ) namespace: Dict[str, Any] = {} exec(grading_code, namespace) ``` The executed code is extracted directly from a Python code block in a task Markdown file: ```python def _extract_grading_code(task: Task) -> str: if not task.automated_checks: return "" match = re.search(r"```python\s*(.*?)\s*```", task.automated_checks, re.DOTALL) if not match: return "" return match.group(1) ``` ### Technical Analysis Automated grading logic is loaded from `tasks/task_*.md`, extracted as arbitrary Python source, and passed to `exec()` without validation, signing, sandboxing, or process isolation. The empty namespace does not provide meaningful protection because Python automatically exposes built-ins, including `__import__`. A malicious or compromised task can therefore import modules, inspect environment variables, read files available to the benchmark user, modify the filesystem, execute subprocesses, or initiate network connections. The project documentation supports adding custom tasks, so task files constitute an extensibility boundary rather than immutable internal source code. This creates a direct code-execution primitive with all privileges of the user running PinchBench. ### Attack Path 1. An attacker supplies, modifies, or contributes a `tasks/task_*.md` file. 2. The task contains an `Automated Checks` section with a crafted Py ...[truncated 1144 chars]
Remediation
View remediation

other

Warning
Location
scripts/lib_upload.py:250
Finding

Unnecessary Host Telemetry Included in Leaderboard Uploads

Content
View full analysis
Dict[str, Any]: """Collect system metadata for submission.""" meta = { "os": sys.platform, "os_release": platform.release(), "os_version": platform.version(), "architecture": platform.machine(), "python_version": platform.python_version(), "python_implementation": platform.python_implementation(), "cpu_count": os.cpu_count(), "hostname_hash": hash(platform.node()) % 10000, } if sys.platform == "linux": meta.update(_collect_linux_info()) elif sys.platform == "darwin": meta.update(_collect_macos_info()) return meta ``` ```python def _collect_linux_info() -> Dict[str, Any]: info: Dict[str, Any] = {} cpuinfo_path = Path("/proc/cpuinfo") meminfo_path = Path("/proc/meminfo") try: cpuinfo = cpuinfo_path.read_text(encoding="utf-8") for line in cpuinfo.splitlines(): if "model name" in line: info["cpu_model"] = line.split(":", 1)[1].strip() b ...[truncated 2402 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib_upload.py:159
Finding

Leaderboard API Token Stored in Plaintext Without Enforced File Permissions

Content
View full analysis
Path: config = _read_config() config["token"] = token if claim_url: config["claim_url"] = claim_url CONFIG_DIR.mkdir(parents=True, exist_ok=True) CONFIG_PATH.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8") return CONFIG_PATH ``` The destination is located under the project script directory: ```python CONFIG_DIR = Path(__file__).resolve().parent / ".pinchbench" CONFIG_PATH = CONFIG_DIR / "config.json" ``` ### Technical Analysis The registration token is written directly to a JSON file in plaintext. The implementation neither requests restrictive permissions nor checks whether an existing directory or file is accessible to other local users. The effective permissions depend on the user's umask and any pre-existing filesystem object. Placing the credential beneath the project directory also increases the possibility that it will be copied into an archive, included in a backup, exposed through a shared workspace, or accidentally committed if ignore rules are incomplete. The token is subsequently accepted as an authentication credential for result submission, so disclosure can enable impersonated leaderboard activity. ### Attack Path 1. The user runs the benchmark registration option. 2. `register_token()` receives a token from the remote API. 3. `save_token_config()` writes the token to `scripts/.pinchbench/config.json`. 4. A local user, process, backup service, shared-workspace participant, or accidental source archive obtains the JSON file. 5. The exposed token is used to submit results under the victim's registration. Exploitation requires read access to the configuration file or accidental disclosure of the project directory; the code does not ...[truncated 542 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib_agent.py:123
Finding

Destructive Cleanup Deletes All Sessions of a Reused OpenClaw Agent

Content
View full analysis
None: """Remove stored session transcripts for an agent to avoid unbounded growth.""" sessions_dir = Path.home() / ".openclaw" / "agents" / agent_id / "sessions" if not sessions_dir.exists(): return removed = 0 for path in sessions_dir.glob("*.jsonl"): try: path.unlink() removed += 1 except OSError as exc: logger.warning("Failed to remove session transcript %s: %s", path, exc) sessions_store = sessions_dir / "sessions.json" if sessions_store.exists(): try: sessions_store.unlink() except OSError as exc: logger.warning("Failed to remove session store %s: %s", sessions_store, exc) if removed: logger.info("Removed %s old OpenClaw session transcripts for %s", removed, agent_id) ``` Agent identifiers are deterministic, and an existing matching agent is reused: ```python model_slug = slugify_model(args.model) agent_id = f"bench-{model_slug}" ... ensure_agent_exists(agent_id, args.model, agent_workspace) cleanup_agent_sessions(agent_id) ``` ### Technical Analysis The cleanup function removes every JSONL transcript and the complete session index for the selected agent. It does not track which sessions were created by the current benchmark run. Because agent IDs are derived deterministically from the model name, `ensure_agent_exists()` may reuse an already existing agent. The subsequent cleanup can therefore delete historical sessions that were not created by the current invocation. Deleting all session records exceeds the minimum filesystem privileges and data scope required to execute an isolated benchmark. The deletion occurs without confirmation or backup. ### Attack Path ...[truncated 1127 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
tasks/task_14_humanizer.md:12
Finding

Benchmark Prompt Encourages Installation of an Unpinned External Skill

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (51)

Tainted flow: 'req' from os.environ.get (line 137, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The upload destination can be overridden via PINCHBENCH_SERVER_URL and the request includes the benchmark payload plus the X-PinchBench-Token header. That means a manipulated environment or caller can silently redirect sensitive results and credentials to an attacker-controlled server, turning this into an exfiltration sink.

Content

Scanner excerpt · scripts/lib_upload.py (reported line 81)May include surrounding context.

python
}
    req = request.Request(endpoint, data=body, headers=headers, method="POST")
    try:
        with request.urlopen(req, timeout=timeout_seconds) as resp:
            response_body = resp.read().decode("utf-8")
            if response_body:
                try:

Tainted flow: 'req' from os.environ.get (line 137, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Registration also permits a server URL override from the environment, causing the client to POST to an arbitrary remote endpoint. While this path does not send an existing token, it can still leak client metadata and cause the tool to trust and store attacker-supplied registration responses, enabling downstream credential misuse.

Content

Scanner excerpt · scripts/lib_upload.py (reported line 139)May include surrounding context.

python
}
    req = request.Request(endpoint, data=body, headers=headers, method="POST")
    try:
        with request.urlopen(req, timeout=timeout_seconds) as resp:
            response_body = resp.read().decode("utf-8")
            data = json.loads(response_body) if response_body else {}
    except error.HTTPError as exc:

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented behavior goes beyond simple local benchmarking by including registration, remote result submission, token handling, and collection/transmission of system metadata. Even if some of this is mentioned later in the file, the top-level description does not clearly and prominently communicate the privacy, authentication, and outbound-data behaviors, creating a meaningful trust and consent gap.

Content

No source excerpt is available for this finding.

exec() call detected

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The code extracts Python from task.automated_checks and executes it with exec() in the current Python process. Because task content is data-driven and potentially attacker-controlled in a benchmark/task pack, this enables arbitrary code execution on the host running grading, including file access, network calls, and environment/token exfiltration.

Content

Scanner excerpt · scripts/lib_grading.py (reported line 94)May include surrounding context.

python
)

    namespace: Dict[str, Any] = {}
    exec(grading_code, namespace)
    grade_func = namespace.get("grade")
    if not callable(grade_func):
        return GradeResult(

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This is a true code-injection issue: automated grading trusts Python embedded inside task metadata and runs it directly. In the skill context, benchmark tasks may be added, shared, or modified externally, so a malicious task can turn grading into a host-level execution primitive.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The system executes untrusted grading code silently, without any user-visible disclosure or consent boundary. This increases risk because operators may run benchmark content assuming it is inert data, when in fact it can execute arbitrary Python during grading.

Content

No source excerpt is available for this finding.

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 · tasks/task_16_email_triage.md (reported line 165)May include surrounding context.

md
Required actions:
      1. Change your SSO password via https://sso.mycompany.com/reset
      2. Rotate your SSH keys on all company repositories
      3. Update any personal access tokens older than 90 days
      4. Confirm completion by replying to this email

      Failure to comply by the deadline may result in temporary account lockout.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The task implements persistent personal-memory storage and cross-session recall, which is outside the stated benchmark-runner purpose in the skill metadata. This mismatch is dangerous because users or operators may enable the skill expecting benchmarking functionality, while it actually normalizes retaining and resurfacing sensitive user data across sessions.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill instructs writing highly sensitive information, including a team secret code phrase, to a persistent file without warning about retention, exposure, or reuse risks. Storing secrets in plaintext on disk materially increases the chance of later disclosure to other tasks, sessions, or users with workspace access.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The task requires the agent to persist and later disclose sensitive personal details and a secret phrase across sessions via a memory file. This is dangerous because cross-session storage plus later disclosure creates a direct mechanism for secret retention and replay, which is especially risky in shared, long-lived, or insufficiently isolated workspaces.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README states that benchmark results auto-upload to a public leaderboard after registration, but it does not clearly warn users that uploaded data will be shared publicly or describe what metadata may be included. In a benchmarking skill for agent workflows, results could contain model identifiers, task outputs, environment details, or other sensitive operational data, so the omission creates a real privacy and data-sharing risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises commands that use shell execution, file access, environment access, and network connectivity, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens reviewability and least-privilege enforcement, making it easier for a benchmark skill to run with broader capabilities than a user may expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill states that results are collected on a public leaderboard, but it does not clearly warn near the usage flow that uploads happen by default unless --no-upload is specified. Users may unintentionally publish benchmark results and associated metadata, which is especially risky in enterprise or private evaluation environments.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · crab.txt (reported line 32)May include surrounding context.

text
@%%        @%%##############%@            @@            
                                            @@%%%########%@@                            
                                               @@@%%%%%@@@

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · crab.txt (reported line 33)May include surrounding context.

text
@%%        @%%##############%@            @@            
                                            @@%%%########%@@                            
                                               @@@%%%%%@@@

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · crab.txt (reported line 34)May include surrounding context.

text
@%%        @%%##############%@            @@            
                                            @@%%%########%@@                            
                                               @@@%%%%%@@@

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

python
def _get_git_version(script_dir: Path) -> str:
    try:
        result = subprocess.run(
            ["git", "rev-parse", "--short", "HEAD"],
            capture_output=True,
            text=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script uploads benchmark results to a remote server by default unless --no-upload is explicitly provided, but it does not present a clear, user-facing confirmation or warning at the point of upload. Because the results include metadata such as model identifier, task details, workspace path, and grading/frontmatter, users may unintentionally transmit potentially sensitive operational information.

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

python
def _get_agent_workspace(agent_id: str) -> Path | None:
    """Get the workspace path for an agent from OpenClaw config."""
    try:
        list_result = subprocess.run(
            ["openclaw", "agents", "list"],
            capture_output=True,
            text=True,

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

python
def _get_agent_workspace(agent_id: str) -> Path | None:
    """Get the workspace path for an agent from OpenClaw config."""
    try:
        list_result = subprocess.run(
            ["openclaw", "agents", "list"],
            capture_output=True,
            text=True,

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

python
normalized_model = normalize_model_id(model_id)
    logger.info("Creating OpenClaw agent %s", agent_id)
    try:
        create_result = subprocess.run(
            [
                "openclaw",
                "agents",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code writes task-specified files into the selected workspace and the module also deletes prior session transcripts automatically, with no user-facing confirmation or safety guard. In this benchmark context, that can overwrite files in an agent workspace and destroy audit artifacts needed for review, especially if task metadata or workspace resolution is untrusted or points somewhere sensitive.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This function sends full task prompt content to an external agent process without any disclosure, consent, or indication of what external systems that agent may use. Given the skill's purpose of benchmarking across real-world calendar, email, research, coding, and multi-step workflows, that materially increases the chance of leaking sensitive prompts/data or triggering actions in connected services.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
88% confidence
Finding

This code forwards arbitrary task.prompt content to an external agent CLI that may in turn access tools, files, networked services, or connected accounts. In a benchmark skill that runs real-world tasks across email, calendar, research, and coding workflows, this can cause sensitive data exposure or unintended real actions if prompts/tasks are untrusted or insufficiently sandboxed.

Content

Scanner excerpt · scripts/lib_agent.py (reported line 382)May include surrounding context.

python
timed_out = False

    try:
        result = subprocess.run(
            [
                "openclaw",
                "agent",

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
86% confidence
Finding

This helper executes arbitrary prompt text via the external OpenClaw agent, which can propagate untrusted content into a capable agent environment. Because it is intended for helper agents such as a judge, the surrounding code may normalize sending hidden evaluation prompts to a live agent without clear consent or restrictions, creating data leakage and unintended-action risk.

Content

Scanner excerpt · scripts/lib_agent.py (reported line 459)May include surrounding context.

python
timed_out = False

    try:
        result = subprocess.run(
            [
                "openclaw",
                "agent",

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
tasks/task_12_skill_search.md:35