Version
1.0.1
Status: pending_audit
Created: 1/16/2026, 8:01:08 PM
LatestaiWARN
Risk: mediumStarted: 1/16/2026, 8:01:53 PMCompleted: 1/16/2026, 8:02:04 PM
View report details
{
"notes": "No obvious exfiltration, obfuscation, filesystem abuse, or prompt injection found. Skill handles session tokens for backend authentication.",
"risks": [
{
"category": "network",
"evidence": "Uses fetch to `${this.apiUrl}` with default `https://gallant-bass-875.convex.site` in src/index.ts and dist/index.js; OAuth calls to `https://github.com/login/device/code` and `https://github.com/login/oauth/access_token` in src/github-oauth.ts/dist/github-oauth.js.",
"severity": "medium",
"recommendation": "Declare required/optional network endpoints and environment variables in the manifest; document and allowlist backend domains; avoid hardcoded default API URL or make it explicit and configurable."
},
{
"category": "network",
"evidence": "Environment variable PLAN2MEAL_API_URL is used but dependencyReport shows no env declarations.",
"severity": "low",
"recommendation": "Add PLAN2MEAL_API_URL (and PLAN2MEAL_AUTH_URL if used) to manifest env requirements to make network usage explicit."
}
],
"summary": "Skill performs network requests to Plan2Meal backend and GitHub OAuth endpoints with a hardcoded default API URL; environment variables for endpoints are not declared in manifest.",
"verdict": "warn",
"allowNetwork": [
"gallant-bass-875.convex.site",
"github.com",
"api.plan2meal.app",
"app.plan2meal.com"
],
"requireHumanReview": true
}dependencyWARN
Risk: mediumStarted: 1/16/2026, 8:01:53 PMCompleted: 1/16/2026, 8:01:53 PM
View report details
{
"requires": {
"env": [],
"bins": [],
"config": [],
"anyBins": []
},
"installers": [],
"references": {
"tools": [],
"connectors": []
},
"dependencies": []
}licensePASS
Risk: lowStarted: n/aCompleted: n/a
View report details
{
"license": "MIT",
"allowlisted": true
}metadataPASS
Risk: lowStarted: n/aCompleted: n/a
View report details
{
"name": "Plan2Meal",
"type": "tool",
"license": "MIT",
"version": "1.0.1",
"homepage": "https://clawdhub.com/okikeSolutions/plan2meal",
"security": {
"openSource": true,
"safeListed": false,
"auditRequired": true,
"requireSource": false,
"requiresAudit": true,
"repositoryHost": null,
"declaredOpenSource": true,
"declaredAuditRequired": null,
"repositoryHostAllowed": null
},
"repository": null,
"description": "Manage recipes and grocery lists via Plan2Meal, a React Native recipe app. Add recipes from URLs, search and organize your collection, and create shopping lists.",
"sourceBytes": 44990,
"capabilities": [
"recipe-management",
"grocery-list-management",
"url-content-extraction"
],
"sourceCommit": null,
"sourceSha256": "20cc4ad2b1d3313bcc0e176bf7a316b34bb7a078a6d35ffb7fa3df4c271463dd"
}sandboxPASS
Risk: lowStarted: 1/16/2026, 8:01:53 PMCompleted: 1/16/2026, 8:01:53 PM
View report details
{
"reason": "sandbox deferred in v1",
"skipped": true
}staticPASS
Risk: lowStarted: 1/16/2026, 8:01:53 PMCompleted: 1/16/2026, 8:01:53 PM
View report details
{
"flags": [],
"fileCount": 26,
"sourceScan": {
"totalFiles": 26,
"scannedFiles": 26,
"skippedBytes": 0,
"skippedFiles": 0,
"suspiciousFiles": [
{
"path": "README.md",
"reasons": [
"network"
],
"excerpts": [
"A ClawdHub skill for managing recipes and grocery lists via chat. Connects to [Plan2Meal](https://plan2meal.app), a React Native recipe app."
]
},
{
"path": "SKILL.md",
"reasons": [
"network",
"secrets"
],
"excerpts": [
"- **Recipe Extraction**: Automatically fetch recipe metadata from URLs",
" - `PLAN2MEAL_API_URL`: Your Plan2Meal backend API URL (e.g., `https://api.plan2meal.app`)",
" - `PLAN2MEAL_AUTH_URL`: Custom authentication URL (defaults to `https://app.plan2meal.com/sign-in`)",
" - **Authentication**: Users authenticate via your Plan2Meal web app, then copy a session token back to Telegram.",
"5. After successful authentication, your backend shows the user a session token",
"6. User copies the token and sends it back to Telegram (or types `token: <token>`)"
]
},
{
"path": "dist/convex.d.ts",
"reasons": [
"network"
],
"excerpts": [
" * Make HTTP request to Plan2Meal backend API",
" private request;",
" * Fetch recipe metadata from URL via backend"
]
},
{
"path": "dist/convex.js",
"reasons": [
"network"
],
"excerpts": [
" * Make HTTP request to Plan2Meal backend API",
" async request(path, options) {",
" const response = await fetch(`${this.apiUrl}${path}`, {"
]
},
{
"path": "dist/device-auth.d.ts",
"reasons": [
"secrets"
],
"excerpts": [
" token: string;",
" token: string;",
" * Refresh access token using refresh token"
]
},
{
"path": "dist/device-auth.js",
"reasons": [
"network",
"secrets"
],
"excerpts": [
" const response = await fetch(`${this.apiUrl}/auth/device/start`, {",
" const response = await fetch(`${this.apiUrl}/auth/device/poll`, {",
" const response = await fetch(`${this.apiUrl}/auth/refresh`, {",
" * Refresh access token using refresh token",
" * Validate an existing token",
" async validateToken(token) {"
]
},
{
"path": "dist/github-oauth.d.ts",
"reasons": [
"secrets"
],
"excerpts": [
" * Poll for access token after user authorizes",
" * Exchange GitHub token for Plan2Meal session token",
" * Full device flow: start, wait for user, exchange token"
]
},
{
"path": "dist/github-oauth.js",
"reasons": [
"network",
"secrets"
],
"excerpts": [
" const response = await fetch('https://github.com/login/device/code', {",
" const response = await fetch('https://github.com/login/oauth/access_token', {",
" const response = await fetch(`${this.apiUrl}/api/auth/github/exchange`, {",
" * Poll for access token after user authorizes",
" * Exchange GitHub token for Plan2Meal session token",
" throw new Error(`Failed to exchange token: ${error}`);"
]
},
{
"path": "dist/index.d.ts",
"reasons": [
"secrets"
],
"excerpts": [
"declare function setUserToken(sessionId: string, token: string): void;"
]
},
{
"path": "dist/index.js",
"reasons": [
"network",
"secrets"
],
"excerpts": [
" apiUrl: process.env.PLAN2MEAL_API_URL || 'https://gallant-bass-875.convex.site',",
"function getApiClient(token) {",
" return new convex_1.default(config.apiUrl, token);",
"function getCommands(token) {"
]
},
{
"path": "dist/test.js",
"reasons": [
"network"
],
"excerpts": [
" apiUrl: process.env.PLAN2MEAL_API_URL || 'https://gallant-bass-875.convex.site',"
]
},
{
"path": "dist/utils.js",
"reasons": [
"crypto"
],
"excerpts": [
" crypto.getRandomValues(array);"
]
},
{
"path": "package-lock.json",
"reasons": [
"network",
"exec"
],
"excerpts": [
" \"resolved\": \"https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz\",",
" \"url\": \"https://opencollective.com/eslint\"",
" \"resolved\": \"https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz\",",
" \"node_modules/cross-spawn\": {",
" \"resolved\": \"https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz\",",
" \"cross-spawn\": \"^7.0.6\","
]
},
{
"path": "src/commands.ts",
"reasons": [
"secrets"
],
"excerpts": [
" validateToken: (token: string) => Promise<boolean>;"
]
},
{
"path": "src/convex.ts",
"reasons": [
"network"
],
"excerpts": [
" * Make HTTP request to Plan2Meal backend API",
" private async request<T>(path: string, options?: RequestInit): Promise<T> {",
" const response = await fetch(`${this.apiUrl}${path}`, {"
]
},
{
"path": "src/device-auth.ts",
"reasons": [
"network",
"secrets"
],
"excerpts": [
" const response = await fetch(`${this.apiUrl}/auth/device/start`, {",
" const response = await fetch(`${this.apiUrl}/auth/device/poll`, {",
" const response = await fetch(`${this.apiUrl}/auth/refresh`, {",
" token: string;",
" token: string;",
" * Refresh access token using refresh token"
]
},
{
"path": "src/index.ts",
"reasons": [
"network",
"secrets"
],
"excerpts": [
" apiUrl: process.env.PLAN2MEAL_API_URL || 'https://gallant-bass-875.convex.site',",
"function getApiClient(token: string) {",
" return new Plan2MealApiClient(config.apiUrl, token);",
"function getCommands(token: string): Plan2MealCommands {"
]
},
{
"path": "src/test.ts",
"reasons": [
"network"
],
"excerpts": [
" apiUrl: process.env.PLAN2MEAL_API_URL || 'https://gallant-bass-875.convex.site',"
]
},
{
"path": "src/utils.ts",
"reasons": [
"crypto"
],
"excerpts": [
" crypto.getRandomValues(array);"
]
}
]
}
}