Back to skill

Security audit

Prayer Times Id

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches its stated reminder purpose, but it creates OpenClaw system events from third-party API data that is not strictly validated and sends configured location coordinates to that provider.

Review this before installing if you are comfortable sending the configured location coordinates to AlAdhan and allowing the skill to create OpenClaw system-event reminders. Prefer using dry-run first, and consider requiring stricter time validation or a data-only notification path before normal use.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

T01 · Skill Instruction Hijacking

Warning
Location
engine.js:235
Finding
Untrusted API Data Is Propagated into a Privileged OpenClaw System Event<![CDATA[ ## Vulnerability Details **File Location**: `engine.js:15-24`, `engine.js:107-121`, and `engine.js:235-258` **Vulnerability Type**: Indirect instruction injection through externally controlled event content **Risk Level**: Medium ### Vulnerable Code ```js function parseTimeToDate(dateObj, hhmm) { const clean = String(hhmm).trim().replace(/\s*\(.+\)$/, ''); const [h, m] = clean.split(':').map((v) => parseInt(v, 10)); if (Number.isNaN(h) || Number.isNaN(m)) { throw new Error(`Format waktu tidak valid: ${hhmm}`); } const d = new Date(dateObj); d.setHours(h, m, 0, 0); return d; } ``` ```js function buildReminderMessage({ prayerLabel, prayerTime, locationName, isRamadan, quote, nowDate }) { const dateId = new Intl.DateTimeFormat('id-ID', { weekday: 'long', day: '2-digit', month: 'long', year: 'numeric' }).format(nowDate); const ramadanBadge = isRamadan ? '🌙 Ramadan: Ya' : '🌙 Ramadan: Tidak'; return [ '🕌 *Z-Cloud Prayer Reminder*', `📍 ${locationName}`, `📅 ${dateId}`, '', `⏰ Waktu *${prayerLabel}* telah tiba (${prayerTime})`, ramadanBadge, '', '📖 *Quote Hari Ini*', `“${quote.text}”`, `— ${quote.source}` ].join('\n'); } ``` ```js for (const prayer of TARGET_PRAYERS) { const apiTime = timingsData.data?.timings?.[prayer.key]; if (!apiTime) continue; const triggerAt = parseTimeToDate(scheduleDate, apiTime); if (triggerAt <= new Date()) continue; const timeLabel = String(apiTime).replace(/\s*\(.+\)$/, ''); const quote = pickQuote(quotes); const message = buildReminderMessage({ prayerLabel: prayer.label, prayerTime: timeLabel, locationName, isRamadan, quote, nowDate: today }); const whenIso = toIsoWithOffset(triggerAt, timezone); const jobName = `prayer-${prayer.label.toLowerCase()}-${whenIso.slice(0, 10)}`; const result = dryRun ? { mode: 'dry-run', command: '(skip)', output: 'not executed' } : scheduleSystemEve ...[truncated 3303 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict full-string format for every API-provided prayer time before parsing: ```js function parsePrayerTime(value) { const input = String(value).trim(); const match = /^(?:([01]\d|2[0-3])):([0-5]\d)(?:\s+\([^)]+\))?$/.exec(input); if (!match) { throw new Error('Invalid prayer-time format received from API'); } return { hour: Number(match[1]), minute: Number(match[2]), label: `${match[1]}:${match[2]}` }; } ``` 2. Reconstruct the displayed time exclusively from validated hour and minute components. Do not reuse the original API string in an agent-facing message. 3. Explicitly reject control characters, including carriage returns, newlines, tabs, null bytes, and other nonprinting characters, in all externally sourced fields. 4. Treat API responses as untrusted data even when delivered over HTTPS. Validate the expected schema, data types, ranges, and string lengths before use. 5. Prefer a plain notification or data-only channel instead of a system-event channel when the content does not need to act as an agent instruction. 6. If system events are required, use a fixed trusted instruction template and place external values in a clearly delimited data structure that the receiving agent is instructed not to interpret as commands. 7. Add regression tests containing numeric-prefix payloads, embedded newlines, Unicode control characters, excessively long values, invalid hours, and invalid minutes. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose understates the operational behaviors: the skill performs outbound network requests, reads local files, and executes an external CLI without declaring those capabilities. This is dangerous because reviewers may authorize a seemingly simple reminder skill while it actually has broader execution and data access powers, increasing the chance of abuse or unintended side effects.

Ae1

High
Category
analysis-evasion
Content
- `engine.js` — engine utama penjadwalan reminder.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares no explicit tool scope or permissions even though it requires network access to external APIs. In an agent ecosystem, missing capability declarations can cause users or orchestrators to approve a skill without understanding that it transmits data externally, weakening trust boundaries and review controls.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The description and content state that the skill is for Indonesia and uses Indonesian-language Islamic quotes, but there is no indication that users can choose another language or opt into the locale restriction. This is a natural-language locale policy concern because the skill appears to enforce a specific language experience by default.

External Transmission

Medium
Category
Data Exfiltration
Content
- Node.js 18+ (disarankan 20+)
- OpenClaw CLI tersedia di PATH (`openclaw`)
- Akses internet ke:
  - `https://api.aladhan.com/v1/timings`
  - `https://api.aladhan.com/v1/gToH`

## Konfigurasi
Confidence
90% confidence
Finding
The skill sends data to an external third-party API, which creates a real data-transmission surface. Even if the transmitted data appears limited to prayer-time lookup inputs such as coordinates and dates, external transmission can expose user location context and introduces dependency on a third-party service's privacy and integrity controls.

External Transmission

Medium
Category
Data Exfiltration
Content
- OpenClaw CLI tersedia di PATH (`openclaw`)
- Akses internet ke:
  - `https://api.aladhan.com/v1/timings`
  - `https://api.aladhan.com/v1/gToH`

## Konfigurasi
Confidence
90% confidence
Finding
A second external endpoint is used for Hijri date conversion, again causing third-party data transmission that is not declared in permissions. In the context of a scheduling skill tied to user location and religious observance, even seemingly modest metadata can be sensitive and should be transparently disclosed and tightly scoped.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Multiple user-visible strings and formatted output are fixed in Indonesian, including errors, reminder content, and the `id-ID` locale, with no indication that the user can choose another language. This is a natural-language policy concern because the skill effectively forces a specific language without opt-in or justification.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code invokes the external `openclaw` binary to add cron/system events that persist beyond the current process, but there is no comment, prompt, or user-facing notice explaining that scheduled system jobs will be created. Creating persistent system events affects system state and should be clearly disclosed to the user.

External Transmission

Medium
Category
Data Exfiltration
Content
queryParams.push(`tune=${encodeURIComponent(tune)}`);
  }

  const timingsUrl = `https://api.aladhan.com/v1/timings?${queryParams.join('&')}`;
  const timingsData = await fetchJson(timingsUrl);

  const gregorian = timingsData.data?.date?.gregorian;
Confidence
91% confidence
Finding
The request to api.aladhan.com includes user location coordinates, which constitutes external transmission of sensitive contextual data. Even over HTTPS, this creates privacy exposure to the external provider and any downstream logging or analytics systems.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill sends precise latitude and longitude to a third-party API to compute prayer times, but the code contains no consent flow, disclosure, minimization, or local-processing fallback. This exposes sensitive location data to an external service and creates privacy risk if users are unaware or if the provider logs requests.

External Transmission

Medium
Category
Data Exfiltration
Content
}

  const hijriDateForLookup = `${gregorian.day}-${gregorian.month.number}-${gregorian.year}`;
  const hijriUrl = `https://api.aladhan.com/v1/gToH?date=${encodeURIComponent(hijriDateForLookup)}`;
  const hijriData = await fetchJson(hijriUrl);

  let isRamadan = false;
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
This JSON file contains user-facing natural-language content exclusively in Indonesian across the quote entries. Under the language/locale policy, a file that effectively forces a specific language without user opt-in or documented regional scope can be considered a policy concern.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
engine.js:121