T09 · Insecure Skill Coding Practices
- Location
SKILL.md:38- Finding
OAuth Secrets Are Exposed in Request URLs and Unnecessarily Persisted
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is coherent Facebook Page automation, but it asks an agent to handle long-lived Page credentials and broad Graph API actions with too little scoping for high-impact page changes.
Review before installing. Use this only for Pages where you are comfortable letting the agent perform publish, delete, moderation, and read operations allowed by the token. Grant the minimum Meta permissions, remove FB_APP_SECRET after setup, keep the credentials file out of backups and repositories, rotate/revoke tokens regularly, and manually confirm any destructive or public-facing action.
SKILL.md:38OAuth Secrets Are Exposed in Request URLs and Unnecessarily Persisted
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
# facebook-page
Facebook Page automation skill for [OpenClaw](https://github.com/openclaw/openclaw).
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## How It Works
1. Loads your credentials from `~/.config/fb-page/credentials.json`
2. Figures out the right Graph API call from what you ask
3. Executes it inline — no script files required
4. If a permission is missing, tells you exactly which one to add and where
Requiring users to provide an App Secret and short-lived User Access Token to the agent for one-time setup expands the set of highly sensitive secrets handled by the skill. If the agent mishandles prompts, logs, transcripts, or memory, these credentials could be disclosed or abused to obtain durable page access.
## Setup (One Time)
You need: **Page ID**, **App ID**, **App Secret**, **short-lived User Access Token**.
The agent will exchange your short-lived token for a never-expiring Page token and save it to `~/.config/fb-page/credentials.json`. File permissions are restricted immediately after saving.
The documentation states the agent will exchange a short-lived token for a 'never-expiring' Page token and persist it locally. Persisting long-lived high-privilege tokens materially increases the blast radius of host compromise, prompt-triggered misuse, or accidental leakage from the agent environment.
You need: **Page ID**, **App ID**, **App Secret**, **short-lived User Access Token**.
The agent will exchange your short-lived token for a never-expiring Page token and save it to `~/.config/fb-page/credentials.json`. File permissions are restricted immediately after saving.
## Credentials File
The documented credential set includes a never-expiring page token and app secret, indicating the skill's steady-state design depends on powerful reusable secrets. In an agentic environment, long-lived reusable tokens are especially dangerous because unintended actions or local compromise can immediately translate into account-level impact.
| Field | Description | Used when |
|---|---|---|
| `FB_PAGE_ID` | Your Facebook Page ID | All API calls |
| `FB_PAGE_TOKEN` | Never-expiring Page Access Token | All API calls |
| `FB_APP_ID` | Meta Developer App ID | One-time token exchange only |
| `FB_APP_SECRET` | Meta Developer App Secret | One-time token exchange only |
The skill explicitly documents reading long-lived credentials from a local JSON file, including a page access token and setup-time app secret. Storing and using persistent tokens from disk creates a real secret-exposure risk: any local compromise, overly broad file permissions, shell history leakage, backups, or accidental sync/commit can lead to takeover of the connected Facebook Page.
---
name: facebook-page
description: "Facebook Page manager: post, schedule, reply, get insights & more. Requires: powershell/pwsh. Reads ~/.config/fb-page/credentials.json (FB_PAGE_TOKEN, FB_PAGE_ID). FB_APP_SECRET for one-time setup only — delete afterward. Long-lived token; rotate periodically and immediately if host is compromised. Grant minimal permissions only. No data forwarded to third parties; all calls go to graph.facebook.com only."
metadata: {"openclaw":{"emoji":"[fb]","requires":{"anyBins":["powershell","pwsh"]}}}
---
This line instructs the agent to load credentials directly from ~/.config/fb-page/credentials.json, meaning the skill is designed to access sensitive authentication material from local storage. That is a genuine credential-handling risk because compromise of the host or file disclosure would expose tokens usable for posting, deleting, moderating, and reading page data.
Credentials are stored in ~/.config/fb-page/credentials.json.
$cfg = Get-Content "$HOME/.config/fb-page/credentials.json" -Raw | ConvertFrom-Json
The code reads FB_PAGE_TOKEN into memory for direct API use. While necessary for functionality, this is still a true credential-access pattern because the skill handles a bearer token that grants significant control over the Facebook Page; bearer-token theft enables unauthorized API actions without additional authentication.
Credentials are stored in ~/.config/fb-page/credentials.json.
$cfg = Get-Content "$HOME/.config/fb-page/credentials.json" -Raw | ConvertFrom-Json
$token = $cfg.FB_PAGE_TOKEN
$pageId = $cfg.FB_PAGE_ID
The documentation specifies a never-expiring Page access token for all API calls. A non-expiring bearer token dramatically increases impact if disclosed, because an attacker can use it indefinitely to post content, delete posts, moderate comments, and query page data until manual revocation.
| Field | Purpose |
|---|---|
| `FB_PAGE_TOKEN` | Never-expiring Page access token — used for all API calls |
| `FB_PAGE_ID` | Numeric Facebook Page ID |
| `FB_APP_ID` | Meta App ID — only needed during token exchange |
| `FB_APP_SECRET` | Meta App Secret — only needed during token exchange |
This line writes FB_PAGE_TOKEN, FB_APP_ID, and FB_APP_SECRET to disk in credentials.json. Persisting the app secret alongside the page token materially increases blast radius: an attacker who gains file access obtains both operational access and a higher-value application secret that should only be used transiently for token exchange.
FB_PAGE_TOKEN = $pageToken FB_APP_ID = $appId FB_APP_SECRET = $appSecret } | ConvertTo-Json | Set-Content "$HOME/.config/fb-page/credentials.json" -Encoding UTF8
**Restrict file permissions immediately after saving:**
This line references the credentials file in the context of permission hardening. Although the surrounding intent is protective, it still confirms the design relies on a local plaintext secret file, which remains a real risk if permissions are not actually enforced, if backups/cloud sync expose the file, or if other local processes can read it.
Restrict file permissions immediately after saving:
# Windows
icacls "$HOME/.config/fb-page/credentials.json" /inheritance:r /grant:r "$($env:USERNAME):(R,W)"
# macOS / Linux
# chmod 600 ~/.config/fb-page/credentials.json
Like the prior finding, this is tied to the same local secret file and indicates reliance on filesystem protection alone for safeguarding long-lived credentials. The context lowers suspicion because it recommends restrictive permissions, but the underlying pattern is still risky because bearer tokens in plaintext remain highly valuable if the host is compromised.
icacls "$HOME/.config/fb-page/credentials.json" /inheritance:r /grant:r "$($env:USERNAME):(R,W)"
> âš ï¸ Never commit this file to version control. It contains long-lived secrets.
The agent rules require always loading credentials first from the local credentials file and acknowledge that FB_APP_SECRET may exist there. This codifies a workflow centered on local secret retrieval, making credential exposure a built-in operational risk rather than an incidental implementation detail.
- **Always load credentials first.** If missing or incomplete, guide setup.
- **Only use `FB_PAGE_TOKEN` and `FB_PAGE_ID`** for API calls. `FB_APP_ID` and `FB_APP_SECRET` are for token exchange only.
- **Never write extra fields** to the credentials file (no owner IDs, conv IDs, or third-party keys).
- **Remove FB_APP_SECRET** from credentials.json after token exchange — it is not needed for API calls.
- **Least-privilege:** only request the permissions your use case needs. Do not request `pages_manage_ads` or `pages_manage_instant_articles` unless explicitly needed.
- **Rotate FB_PAGE_TOKEN** periodically via Graph API Explorer, and immediately if the host is ever compromised.
- **All API calls go to `graph.facebook.com` only.** No external forwarding, no third-party services.
The README advertises that users can ask for 'anything the Meta Graph API supports,' which creates an extremely broad action surface for an agentic skill. In practice, this can cause unintended activation or unsafe execution of destructive or privacy-impacting Facebook Page operations because the allowed command scope is not narrowly constrained.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
- **Posts** — text, image, link, video, scheduled
- **Comments** — get, reply, hide, delete
- **Insights** — page stats, post performance
- **Events** — list, create
- **Page info** — name, followers, about
- **Token management** — refresh expired tokens
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
icacls "$HOME/.config/fb-page/credentials.json" /inheritance:r /grant:r "$($env:USERNAME):(R,W)"
> âš ï¸ Never commit this file to version control. It contains long-lived secrets.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
"credentialSetup": {
"type": "manual",
"docsUrl": "https://developers.facebook.com/tools/explorer/",
"description": "One-time OAuth2 token exchange via Meta Graph API Explorer. After exchange, FB_APP_SECRET may be removed from credentials.json. Restrict file permissions with icacls (Windows) or chmod 600 (macOS/Linux) immediately after saving."
},
"requires": {
"binaries": [
No suspicious patterns detected.