Back to skill

Security audit

Wakehook

Security checks for vulnerabilities and agentic risk

Overview

Wakehook largely matches its stated wake-automation purpose, but it needs review because it handles sensitive sleep data and long-lived OAuth tokens while leaving a test trigger unauthenticated when its webhook token is unset.

Review before installing. Use poll mode where possible, bind the service to trusted interfaces, set strong webhook/admin tokens, disable or protect /test/replay, send events only to trusted HTTPS endpoints, pin package/container versions, and protect or encrypt the SQLite database that stores Google refresh tokens.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:26
Finding

Unverified Remote Installer Is Downloaded and Executed Through a Shell

Content
View full analysis
Remediation
View remediation
pinned-bun-release" | sha256sum -c - # Install only after verification succeeds. ``` ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/server.ts:27
Finding

Fail-Open Authentication Permits Unauthorized Synthetic Wake and Agent Triggers

Content
View full analysis
{ if (!authorized(c.req.raw)) return c.text("unauthorized", 401); const body = (await c.req.json().catch(() => ({}))) as Partial; const end = body.end ?? new Date().toISOString(); const durationMin = body.durationMin ?? 420; const start = body.start ?? new Date(new Date(end).getTime() - durationMin * 60000).toISOString(); const session: SleepSession = { id: body.id ?? `test:${end}`, user: body.user ?? "test-user", start, end, durationMin, isMainSleep: body.isMainSleep ?? true, }; const fired = await engine.process([session], source.name); return c.json({ fired, session }); }); ``` The token defaults to an empty value: ```ts webhookAuthToken: env( "GOOGLE_WEBHOOK_AUTH_TOKEN", file.google?.webhookAuthToken ?? "", ), ``` ### Technical Analysis Authentication explicitly succeeds when `webhookAuthToken` is empty. Consequently, an omitted or misconfigured token changes protected routes into unauthenticated routes rather than preventing startup or rejecting requests. `/test/replay` is always registered, including in the recommended polling deployment. It accepts caller-controlled sleep-session fields and passes the resulting session to `Engine.process()`. If the supplied session satisfies the ...[truncated 2266 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/db.ts:22
Finding

Long-Lived Google OAuth Tokens Are Stored in Plaintext Without Enforced File Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
Dockerfile:5
Finding

Container Build Falls Back to Unlocked Dependency Resolution

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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (33)

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

bash
bunx wakehook                 # run without installing — or: bun add wakehook
# or Docker:
docker run -v wakehook-data:/data --env-file .env ghcr.io/robbeverhelst/wakehook

2 · Configure — create config.json in your working directory:

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose centers on a wakehook integration that connects sleep-data providers to an agent via webhook and triggers wake-based automations. The supplied code does none of that. It is a generic time utility module for timezone formatting and parsing local times. While such helpers could support scheduling logic elsewhere, this chunk by itself does not implement the described wakehook behavior, external integrations, authorization, or webhook delivery. That is a material description-behavior mismatch rather than a mere supporting detail.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
98% confidence
Finding

The skill recommends curl ... | bash, which executes a remote script directly from the network without prior verification. This is a classic supply-chain risk: if the endpoint, CDN, or transport path is compromised, arbitrary code will run immediately on the user's machine.

Content

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

md
## Prerequisites (check, don't assume)

1. **Bun ≥ 1.3** — `bun --version`; install with `curl -fsSL https://bun.sh/install | bash`.
   wakehook is Bun-only (`bun:sqlite`); never run it with Node.
2. **Google OAuth credentials** — a Google Cloud project with the **Health API**
   enabled and the `googlehealth.sleep.readonly` scope, plus an **OAuth 2.0

Credential Access

High
Category
Privilege Escalation
Confidence
80% confidence
Finding

The instructions pass .env secrets into a long-running container while also mounting persistent storage, which can expose OAuth credentials and refresh-token material to containerized code. If the image is compromised, mutable, or overly privileged, those secrets may be read and abused for persistent access to the user's Google health data and webhook integrations.

Content

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

bunx wakehook

text

(Docker alt: `docker run -v wakehook-data:/data --env-file .env ghcr.io/robbeverhelst/wakehook`.)
Keep it running (long-lived process / service). In poll mode it polls Google
every `pollIntervalMs` **around the morning window only** (set `pollWindowOnly:
false` to poll all day) and, on the morning wake, POSTs the agent once.

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 · src/sources/google/oauth.ts (reported line 3)May include surrounding context.

ts
/**
 * Google OAuth 2.0 token handling. The one-time `auth` CLI mints the refresh
 * token; at runtime we transparently refresh the access token as it nears expiry.
 *
 * NOTE: publish the OAuth app to "In Production" (still unverified, 100-user cap)
 * so the refresh token does not expire after 7 days (the "Testing" default).

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 · src/sources/google/oauth.ts (reported line 73)May include surrounding context.

ts
/**
 * Google OAuth 2.0 token handling. The one-time `auth` CLI mints the refresh
 * token; at runtime we transparently refresh the access token as it nears expiry.
 *
 * NOTE: publish the OAuth app to "In Production" (still unverified, 100-user cap)
 * so the refresh token does not expire after 7 days (the "Testing" default).

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The design materially expands the skill from an agent-specific wake trigger into a vendor-neutral event bus that broadcasts health-derived wake events to multiple consumers. That scope expansion increases attack surface and data exposure risk because users invoking an OpenClaw/Hermes skill would not reasonably expect multi-subscriber redistribution of sensitive sleep/wake data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Wake times and sleep-session details are sensitive health-adjacent data, and the design explicitly broadcasts them to every subscriber without indicating any explicit user-facing privacy warning or consent flow. In the context of a skill marketed as agent wake automation, silent redistribution to arbitrary URLs is especially dangerous because users may not understand that intimate behavioral data can be copied to multiple external services.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Documented fan-out to arbitrary subscriber URLs exceeds the stated skill purpose and creates a concrete exfiltration path for sensitive health-inferred events. Because each subscriber can be independently configured, a misled user or downstream automation could unknowingly send wake/health metadata to third parties, making the mismatch security-relevant rather than merely architectural.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README promotes broadcasting health-derived wake events to arbitrary subscribers but does not prominently warn that wake times and inferred sleep information are sensitive personal data. In this skill context, the feature is explicitly about transmitting health-adjacent behavioral data to other services, so lack of privacy guidance increases the risk of accidental disclosure to third parties or insecure endpoints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example payload includes a user identifier, wake timestamp, and session duration details, but the documentation does not warn that these fields can reveal sensitive health and behavioral patterns when forwarded to subscribers. Because the skill is designed to integrate with arbitrary URLs and automation platforms, users may unintentionally leak personal data into logs, third-party workflows, or unsecured webhook endpoints.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

The README instructs users to run a container image from GHCR without a pinned tag or digest, which makes the deployed artifact mutable over time. That creates a supply-chain risk: a later image change, compromised registry account, or unexpected breaking update could cause users to run unreviewed code.

Content

No source excerpt is available for this finding.

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 · README.md (reported line 202)May include surrounding context.

🧪 Test it without waiting for morning

bash
curl -X POST http://localhost:8080/test/replay \
  -H "Authorization: Bearer $GOOGLE_WEBHOOK_AUTH_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{}'    # fires a synthetic wake "now"; pass {"end":"...","durationMin":420} to control it

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to handle environment-based secrets and perform network interactions, but it does not declare any explicit tool scope or permission boundary. In a skill system, missing scope declarations increase the chance that an agent executes sensitive actions without clear user visibility or sandbox restrictions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill processes sensitive sleep/health data and instructs the user to store OAuth-derived access material, including a refresh token in a local database, without a clear privacy and retention warning. Health telemetry and long-lived tokens are sensitive; mishandling them can expose private behavioral data and enable ongoing account access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The webhook-mode instructions tell the user to expose a public HTTPS endpoint and register it with an external provider, but they understate the security implications of exposing an internet-reachable service. A publicly accessible webhook increases attack surface for probing, replay attempts, brute-forcing weak tokens, and misconfiguration that could trigger unauthorized events.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
83% confidence
Finding

The Docker example pulls and runs ghcr.io/robbeverhelst/wakehook without a fixed tag or digest, so future executions may fetch different, unreviewed code. This creates a supply-chain risk where a compromised or changed image could gain access to mounted data and .env secrets.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 251)May include surrounding context.

Verify without waiting for morning

bash
curl -X POST http://localhost:8080/test/replay \
  -H 'Content-Type: application/json' -d '{}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code persists OAuth access and refresh tokens in a local SQLite database in plaintext, with no visible encryption, OS keychain integration, access control hardening, or user-facing disclosure. If the host, container filesystem, backup, or local account is compromised, an attacker could recover long-lived refresh tokens and impersonate the user against Google/Fitbit APIs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The webhook handler parses inbound notifications and then uses the referenced user identifier to obtain an access token and fetch sleep data from the Google Health API. While the code comments describe the mechanism, there is no user-facing confirmation, warning, or disclosure near this path that external notifications will cause retrieval of personal health data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest positions the skill as enabling wake-triggered automations for the user's agent. The design explicitly documents a generic preset posting raw signed events to arbitrary subscriber URLs, with OpenClaw-specific translation only as an optional preset, indicating a more general integration platform than advertised.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The config sets "timezone": "Europe/Brussels", which imposes a specific locale setting in natural-language terms without any indication here that the user can opt in or override it. Under the policy rule for language/locale constraints, a fixed locale can be a violation unless it is explicitly optional or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The runtime dependency hono is specified with a caret range, which allows automatic installation of newer releases within the major version. That weakens reproducibility and can expose deployments to newly introduced vulnerabilities or malicious upstream changes, especially significant here because this skill exposes a webhook-facing service.

Content

Scanner excerpt · package.json (reported line 55)May include surrounding context.

json
"test": "bun test"
  },
  "dependencies": {
    "hono": "^4.6.14"
  },
  "devDependencies": {
    "@semantic-release/changelog": "^6.0.3",

Unverifiable Dependency: hono has 16 known advisory(ies) (CVE-2024-48913 (Hono allows bypass of CSRF Middleware by a request without Content-Type header.); CVE-2026-56762 (Hono missing validation of cookie name on write path in setCookie()); CVE-2026-47676 (Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The manifest uses an unpinned hono version even though advisories exist for that package, making it impossible to verify whether the installed version is affected. In this skill's context, hono is the web framework for an inbound webhook service, so framework-level issues such as CSRF, cookie handling, or routing flaws could directly affect externally reachable endpoints.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
86% confidence
Finding

The dev dependency @semantic-release/changelog is not pinned to an exact version, so CI or release environments may resolve different package versions over time. This is primarily a software supply-chain hygiene issue affecting release integrity rather than direct runtime compromise.

Content

Scanner excerpt · package.json (reported line 58)May include surrounding context.

json
"hono": "^4.6.14"
  },
  "devDependencies": {
    "@semantic-release/changelog": "^6.0.3",
    "@semantic-release/exec": "^7.0.0",
    "@semantic-release/git": "^10.0.1",
    "@semantic-release/npm": "^13.1.0",

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
src/cli/auth.ts:49

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
src/sources/google/oauth.ts:48