Back to skill

Security audit

Resy Hunter

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent reservation monitor, but it handles restaurant account credentials and reusable sessions with weak containment and storage safeguards.

Review before installing. Use this only if you are comfortable giving the skill Resy credentials, a static Resy API key, Telegram alert access, and an OpenTable session file. Keep its data directory private, avoid committing or sharing ~/.openclaw/data/resy-hunter, consider disabling or removing the cron job when not needed, and prefer running the Playwright browser in a contained environment until --no-sandbox and secret-file permissions are fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/resy-auth.sh:13
Finding

Authentication Tokens and Browser Session State Are Stored Without Explicit Access Restrictions

Content
View full analysis
"$TOKEN_FILE" ``` From `scripts/opentable-login.js`: ```javascript const DATA_DIR = path.join(process.env.HOME, '.openclaw/data/resy-hunter'); const SESSION_FILE = path.join(DATA_DIR, 'opentable-session.json'); async function main() { fs.mkdirSync(DATA_DIR, { recursive: true }); ``` ```javascript // Save session await context.storageState({ path: SESSION_FILE }); ``` From `scripts/opentable-check.js`: ```javascript // Refresh session for next run try { await context.storageState({ path: SESSION_FILE }); } catch (e) { // Non-critical } ``` ### Technical Analysis The Resy bearer token and OpenTable Playwright storage state are deliberately persisted so scheduled monitoring can run without interactive authentication. This persistence is functionally justified, but the implementation does not enforce owner-only permissions. The Resy token is written through ordinary shell redirection, while the OpenTable state is written by Playwright. The directory is created with the process's default permissions, and no restrictive `umask`, `chmod`, explicit file mode, or symbolic-link protection is applied. Consequently, the actual protection depends on the invoking environment's umask ...[truncated 1734 chars]
Remediation
View remediation
"$tmp_file" mv -f "$tmp_file" "$TOKEN_FILE" chmod 600 "$TOKEN_FILE" ``` 3. In JavaScript, create the directory with mode `0700` and apply mode `0600` after Playwright writes the state: ```javascript fs.mkdirSync(DATA_DIR, { recursive: true, mode: 0o700 }); await context.storageState({ path: SESSION_FILE }); fs.chmodSync(SESSION_FILE, 0o600); ``` 4. Reject symbolic links before reading, migrating, or overwriting sensitive files by using `lstat` and verifying that the destination is a regular file in the expected directory. 5. Avoid copying a legacy token unless the source and destination are regular, owner-controlled files. Reapply restrictive permissions after migration. 6. Document the sensitivity, expiration, revocation, and secure-deletion procedures for both state files. Prefer an operating-system credential store where available. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/resy-check.sh:89
Finding

Resy Slot Configuration Tokens Are Exposed and Persisted Despite Not Being Required for Monitoring

Content
View full analysis
"$STATE_FILE" ``` ### Technical Analysis The Resy availability response contains `.config.token`, an opaque server-issued value associated with an individual reservation configuration. `resy-check.sh` copies this value into every slot returned to stdout. The monitor subsequently incorporates complete slot objects into its report and writes them into `~/.openclaw/data/resy-hunter/.last-seen.json`. The token therefore crosses multiple unnecessary boundaries: - Resy API response to script output; - script output to monitor state; - monitor state to persistent plaintext storage; - potentially monitor output to Agent logs or conversation context. The Skill only needs slot times, reservation type, deposit information, and venue metadata to detect and report availability. Deduplication uses `time_start`; generated booking links also do not use `config_token`. Retaining the field therefore exceeds the minimum data necessary for the declared read-only monitoring functionality. Because the repository does not implement booking or document the token's exact authorization semantics, it cannot be stated conclusively that the token alone enables ...[truncated 1458 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/opentable-login.js:26
Finding

Chromium Is Launched With the Process Sandbox Disabled

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The code’s behavior is narrowly focused on querying OpenTable availability. It launches a headless browser, loads a saved OpenTable session, visits an OpenTable reservation URL, captures availability data from network responses or DOM elements, detects login/session expiration, and prints structured slot data. That aligns with part of the declared purpose ('check availability' on OpenTable), but the declared description presents a broader skill that also manages a watchlist, sends Telegram alerts, and covers Resy and Tock. None of those additional capabilities appear in this supplied code chunk. Because the actual code only implements a subset of the declared functionality and omits major declared capabilities, this is a description-behavior mismatch for the supplied chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The code is related to the general reservation-monitoring domain, but the declared description significantly overstates what this specific code chunk does. The script does not manage a watchlist or send Telegram alerts; it simply queries Tock availability and prints results. It also contains only Tock-specific logic, with no Resy or OpenTable support in the supplied chunk. Additionally, it relies on headless browser automation and anti-bot challenge detection to access public Tock pages, which is a materially different implementation capability than the description suggests. Therefore, the description does not accurately represent the behavior of this code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| OpenTable | `opentable-check.js` | `restaurant_id` (integer) | Yes — manual login via `opentable-login.js` | One-time visible browser login, session persisted

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| Tock | `tock-check.js` | `slug` (URL slug) | No | Playwright bypasses Cloudflare |

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation explicitly instructs users to extract a static API key from browser network traffic for an unofficial, reverse-engineered API. That is dangerous because it normalizes bypassing intended access controls and operational boundaries, and a non-expiring credential materially increases the blast radius if reused, leaked, or embedded in the skill.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/resy-check.sh (reported line 53)May include surrounding context.

sh
# On 419 (token expired), force re-auth and retry once
if [[ "$http_code" == "419" ]]; then
  rm -f "${DATA_DIR}/.resy-token"
  RESY_AUTH_TOKEN=$(bash "${SCRIPTS_DIR}/resy-auth.sh" --force 2>&1) || {
    echo "$RESY_AUTH_TOKEN" >&2
    exit 1

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly relies on environment variables, shell execution, Node, curl, and cron-like background tasks, but it does not declare any explicit tool scope or allowed-tools boundary. That creates an authorization gap where an agent may grant broader execution capability than users expect, increasing the blast radius of prompt injection or misuse in a skill that handles credentials and persistent monitoring.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs users to extract and provide a Resy API key plus account email and password, but it does not include strong guidance on secure handling, least-privilege storage, or the risks of exposing credentials to the agent/runtime. In this context, the danger is elevated because the skill also uses shell execution, persistent auth caching, and background monitoring, so stolen or mishandled credentials could enable ongoing account access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill directs users to persist OpenTable session cookies to a local file without warning that those cookies may function as bearer tokens granting account access to anyone who can read them. Because the skill runs headless automation and background monitoring, compromise of that session file could silently enable unauthorized access until expiry or revocation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding

The setup instructions invoke Playwright through npx without pinning a version, which can pull whatever package version is current at execution time. That creates a supply-chain risk and undermines reproducibility, since a compromised or breaking upstream release could execute unexpected install scripts or alter browser automation behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation explicitly describes persisting an authenticated OpenTable browser session to a local file, but it does not warn that the file may contain reusable cookies or localStorage tokens that could let another local user or malware hijack the account session. In a skill that automates login with stored credentials, this omission increases the chance that users leave sensitive session artifacts unprotected or commit them accidentally.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The reference documentation expands a reservation-monitoring skill into credential-based account authentication by instructing use of a Resy email/password and token retrieval flow. Even if framed as functional setup, this broadens the skill into handling sensitive account secrets and session issuance, increasing the chance of credential theft, misuse, or unauthorized account actions beyond simple public availability checks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file describes using persistent API credentials, auth tokens, and account passwords, but provides no security guidance on storage, rotation, scope, redaction, or user consent. In a skill that may automate monitoring and alerts, this omission makes accidental secret exposure, insecure caching, and downstream compromise of the user's Resy account significantly more likely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script harvests a Telegram bot token from unrelated OpenClaw configuration files if its own environment variable is unset. This creates a cross-context secret exposure path: a user invoking this skill may unknowingly cause the skill to reuse a more privileged or unrelated bot credential and transmit data under that identity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script silently pulls credentials from environment variables and local OpenClaw config without explicit disclosure, which can cause users to unknowingly authorize use of existing secrets. In combination with the fallback config search, this weakens consent and increases the chance of accidental secret reuse across tools.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/notify.sh (reported line 61)May include surrounding context.

sh
exit 1
fi

response=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
  -H "Content-Type: application/json" \
  -d "$(jq -n \
    --arg chat_id "$CHAT_ID" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/notify.sh (reported line 61)May include surrounding context.

sh
exit 1
fi

response=$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
  -H "Content-Type: application/json" \
  -d "$(jq -n \
    --arg chat_id "$CHAT_ID" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script performs an outbound HTTP request to the Telegram API containing the user's message text and destination chat ID. Although the header comments describe usage, there is no runtime confirmation, user-facing notice, or explicit warning about sending data to an external service.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

This is a true session-persistence issue: the automation intentionally reuses a saved authenticated session to act as the user on a third-party service. In the context of a reservation-monitoring skill, that behavior is functional rather than obviously malicious, but it still creates a tangible security risk because the session file becomes a bearer secret for the account.

Content

Scanner excerpt · scripts/opentable-check.js (reported line 67)May include surrounding context.

js
],
    });

    // Load saved session
    const context = await browser.newContext({
      userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
      viewport: { width: 1280, height: 800 },

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script loads an authenticated Playwright storage state from a persistent file in the user's home directory, which can contain session cookies or tokens that grant account access. Persisting and reusing that state without clear disclosure, lifecycle controls, or protection checks increases the risk of credential/session theft from disk or unintended account reuse by other local processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script refreshes and writes updated authenticated browser session data back to disk, extending the lifetime of reusable session material. If the local filesystem is accessible to another user, process, backup system, or malware, the stored session could be replayed to access the user's OpenTable account without reauthentication.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This shell script requires RESY_EMAIL and RESY_PASSWORD, then later sends them in an HTTP POST to Resy. Although the header comment lists required variables, it does not clearly warn the user that account credentials will be used for remote authentication and that a token will be cached locally.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/resy-check.sh (reported line 40)May include surrounding context.

sh
_resy_find() {
  local auth_header='Authorization: ResyAPI api_key="'"${RESY_API_KEY}"'"'
  local payload='{"lat":0,"long":0,"day":"'"${DATE}"'","party_size":'"${PARTY_SIZE}"',"venue_id":'"${VENUE_ID}"'}'
  curl -s -w "\n%{http_code}" -X POST "https://api.resy.com/4/find" \
    -H "${auth_header}" \
    -H "x-resy-auth-token: ${RESY_AUTH_TOKEN}" \
    -H "Content-Type: application/json" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/resy-auth.sh (reported line 62)May include surrounding context.

sh
fi

auth_header='Authorization: ResyAPI api_key="'"${RESY_API_KEY}"'"'
response=$(curl -s -w "\n%{http_code}" -G "https://api.resy.com/3/venuesearch/search" \
  --data-urlencode "query=${QUERY}" \
  --data-urlencode "geo.lat=${LAT}" \
  --data-urlencode "geo.long=${LONG}" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/resy-check.sh (reported line 40)May include surrounding context.

sh
fi

auth_header='Authorization: ResyAPI api_key="'"${RESY_API_KEY}"'"'
response=$(curl -s -w "\n%{http_code}" -G "https://api.resy.com/3/venuesearch/search" \
  --data-urlencode "query=${QUERY}" \
  --data-urlencode "geo.lat=${LAT}" \
  --data-urlencode "geo.long=${LONG}" \

Static analysis

No suspicious patterns detected.