Back to skill

Security audit

FB Inbox Forward

Security checks for vulnerabilities and agentic risk

Overview

The skill has a clear forwarding purpose, but it handles Facebook Page tokens and private messages through a persistent listener with insecure token and runtime handling that should be reviewed before installation.

Install only if you are comfortable giving this skill access to a Facebook Page token and forwarding full inbound message text to the configured OpenClaw destination. Review or patch it to use Authorization headers, sanitized error logging, bounded message delivery, and a fixed or integrity-checked worker script before running the listener.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:137
Finding
Facebook access token may be exposed through request URLs and exception logging<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 74–75 and 137–169 **Vulnerability Type**: Credential exposure through URL query parameters and unsanitized error logging **Risk Level**: High ### Vulnerable Code ```powershell $fb = Get-Content "$HOME/.config/fb-page/credentials.json" -Raw | ConvertFrom-Json $r = Invoke-RestMethod "https://graph.facebook.com/v25.0/me?access_token=$($fb.FB_PAGE_TOKEN)" -ErrorAction Stop ``` ```powershell try { $convs = (Invoke-RestMethod "https://graph.facebook.com/v25.0/$pageId/conversations?fields=id,updated_time&limit=20&access_token=$token").data foreach ($conv in $convs) { $lastSeen = if ($state."$($conv.id)") { [datetime]::Parse($state."$($conv.id)") } else { (Get-Date).ToUniversalTime().AddSeconds(-$lookback) } if ([datetime]::Parse($conv.updated_time) -le $lastSeen) { continue } $msgs = (Invoke-RestMethod "https://graph.facebook.com/v25.0/$($conv.id)/messages?fields=message,from,created_time&limit=10&access_token=$token").data foreach ($msg in ($msgs | Sort-Object created_time)) { if ([datetime]::Parse($msg.created_time) -le $lastSeen) { continue } $senderId = if ($msg.from) { $msg.from.id } else { '' } if ($senderId -eq $pageId) { continue } $sender = if ($msg.from) { $msg.from.name } else { 'Unknown' } $text = if ($msg.message) { $msg.message } elseif ($msg.sticker) { '[sticker]' } else { '[attachment]' } Write-Log "FORWARD | $sender | Conv:$($conv.id)" $notify = "New FB Message`nFrom: $sender`nMessage: $text`nConv ID: $($conv.id)" Start-Job -ScriptBlock { param($ch, $tg, $m) & openclaw message send --channel $ch --target $tg --message $m 2>$null } -ArgumentList $channel, $target, $notify | Out-Null } $state | Add-Member -NotePropertyName $conv.id -NotePrope ...[truncated 2563 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass the token in an authorization header rather than a URL query parameter: ```powershell $headers = @{ Authorization = "Bearer $token" } $convsUri = "https://graph.facebook.com/v25.0/$pageId/conversations?fields=id,updated_time&limit=20" $convs = (Invoke-RestMethod -Uri $convsUri -Headers $headers -Method Get -ErrorAction Stop).data ``` Apply the same pattern to the credential test and message retrieval request. 2. Never write the complete exception object directly to disk. Record only an allowlisted error category, HTTP status code, and sanitized API error code. 3. Add a redaction function that removes authorization headers, `access_token` parameters, token values, and full request URIs before any diagnostic text is logged. 4. Restrict logging to messages such as: ```powershell catch { $status = if ($_.Exception.Response) { [int]$_.Exception.Response.StatusCode } else { "unknown" } Write-Log "Facebook API request failed. HTTP status: $status" } ``` 5. Review and securely delete existing logs, then rotate the Facebook Page token if a log may already contain it. 6. Continue applying restrictive file permissions, but do not rely on permissions as a substitute for preventing credentials from entering logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:158
Finding
Unbounded PowerShell background-job accumulation enables resource exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 158–162 **Vulnerability Type**: Unbounded resource consumption in a persistent message listener **Risk Level**: Medium ### Vulnerable Code ```powershell # TRANSMIT: sender name + message text + conv ID to configured channel only $notify = "New FB Message`nFrom: $sender`nMessage: $text`nConv ID: $($conv.id)" Start-Job -ScriptBlock { param($ch, $tg, $m) & openclaw message send --channel $ch --target $tg --message $m 2>$null } -ArgumentList $channel, $target, $notify | Out-Null ``` ### Technical Analysis The persistent listener creates a new PowerShell background job for every Facebook message it forwards. Redirecting the returned job object to `Out-Null` does not remove the job from the PowerShell job repository. The code never calls `Wait-Job`, `Receive-Job`, or `Remove-Job`, and it does not impose a concurrency limit. Completed jobs and their retained state can therefore accumulate for the lifetime of the worker. If `openclaw message send` blocks or the destination is unavailable, active jobs can also accumulate concurrently. This creates an avoidable denial-of-service condition. As the worker's purpose is continuous forwarding, it should use synchronous execution or explicitly bounded and cleaned-up asynchronous execution. ### Attack Path 1. The user starts the background listener. 2. An attacker or automated account repeatedly sends messages to the monitored Facebook Page. 3. The worker detects the messages and creates one `Start-Job` instance for each forwarded message. 4. Completed jobs remain registered because the worker never receives or removes them. 5. If the OpenClaw destination is slow or unavailable, multiple active jobs additionally remain in memory. 6. Job metadata, process resources, and buffered output state progressively consume memory and other operating-system resources. 7. The worker or its host becomes degraded or unavailable, interrupting message forward ...[truncated 625 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer synchronous delivery if message ordering and reliability are more important than parallelism: ```powershell & openclaw message send --channel $channel --target $target --message $notify 2>$null if ($LASTEXITCODE -ne 0) { Write-Log "Message delivery failed." } ``` 2. If asynchronous execution is required, impose a strict concurrency limit and clean up every completed job using `Receive-Job` and `Remove-Job`. 3. Periodically enumerate completed, failed, and stopped jobs and remove them: ```powershell Get-Job | Where-Object State -in @('Completed', 'Failed', 'Stopped') | ForEach-Object { Receive-Job -Job $_ -ErrorAction SilentlyContinue | Out-Null Remove-Job -Job $_ -Force } ``` 4. Add a timeout for each OpenClaw delivery operation so an unavailable destination cannot leave jobs running indefinitely. 5. Apply backpressure through a bounded queue. Define a maximum queue size and a clear overflow policy rather than spawning unlimited work. 6. Consider deduplication, rate limiting, and batching to reduce the effect of abusive or unusually high inbound message volume. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (13)

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
---
name: fb-inbox-forward
description: "Forward Facebook Page inbox messages to your OpenClaw channel in real time. Requires: powershell/pwsh + openclaw CLI. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID) and ~/.config/fb-inbox-forward/config.json (NOTIFY_CHANNEL, NOTIFY_TARGET). Listener opt-in only — never starts autonomously. Logs metadata only; no message content written to disk. All calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb-fwd]","requires":{"anyBins":["powershell","pwsh"]}}}
---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Test credentials:
```powershell
$fb = Get-Content "$HOME/.config/fb-page/credentials.json" -Raw | ConvertFrom-Json
$r  = Invoke-RestMethod "https://graph.facebook.com/v25.0/me?access_token=$($fb.FB_PAGE_TOKEN)" -ErrorAction Stop
Write-Host "Connected as: $($r.name)"
```
Confidence
91% confidence
Finding
The test-credentials command places the access token directly in the request URL query string. Tokens in URLs are commonly captured in shell history, verbose logs, proxy logs, diagnostic output, or exception messages, increasing the chance of credential disclosure even if the destination host is legitimate.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
"Credentials read fresh from disk at runtime — never embedded as literals in any script. All runtime files permission-restricted. Logs contain sender name and conv ID only."
                          },
    "persistence":  {
                        "type":  "background-process",
                        "code":  "inline",
                        "optional":  true,
                        "description":  "Polls Facebook Page conversations every POLL_INTERVAL_SEC seconds (default 15). Transmits: sender name + full message text + conv ID to NOTIFY_CHANNEL/NOTIFY_TARGET via openclaw message send. Message text goes to the channel destination only — never written to disk. Logs record sender name and conv ID only. Worker stored at ~/.config/fb-inbox-forward/worker.ps1 with restricted permissions. Credentials read fresh from disk at runtime — no tokens embedded as literals. Never starts autonomously — opt-in only."
                    },
    "requires":  {
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
$f = "$dir/$_"; if (Test-Path $f) { icacls $f /inheritance:r /grant:r "$($env:USERNAME):(R,W)" | Out-Null }
    }
} else {
    Get-ChildItem $dir | ForEach-Object { & chmod 600 $_.FullName }
}
```
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Skill Enumeration

Medium
Category
Agent Snooping
Content
$pidFile   = "$configDir/listener.pid"

# Write worker — exact content as shown in WORKER SCRIPT section above
$workerContent = Get-Content "$HOME/.openclaw/skills/fb-inbox-forward/SKILL.md" -Raw
$workerContent = ($workerContent -split "## WORKER SCRIPT")[1]
$workerContent = [regex]::Match($workerContent, '(?s)```powershell\r?\n(.*?)```').Groups[1].Value
Set-Content $worker -Value $workerContent -Encoding UTF8
Confidence
90% confidence
Finding
The start routine reconstructs worker.ps1 by parsing ~/.openclaw/skills/fb-inbox-forward/SKILL.md at runtime instead of using a fixed embedded script or integrity-checked artifact. If that skill file is modified locally by another process or attacker, the listener will execute attacker-controlled PowerShell with the same access to Facebook credentials and message forwarding, turning a documentation file into an execution source.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
} else {
    $worker, $logFile, $stateFile, $pidFile | ForEach-Object {
        New-Item $_ -Force -ItemType File -ErrorAction SilentlyContinue | Out-Null
        & chmod 600 $_
    }
    $proc = Start-Process pwsh -ArgumentList "-NonInteractive -File `"$worker`"" -PassThru -RedirectStandardOutput "/dev/null" -RedirectStandardError "/dev/null"
}
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.