Claude Code, Skill
Expo Mobile App Builder
A mobile app agency for iOS and Android
Compatibility: Not stated.
Grade B
Minor issues only, no Medium or High. Worth a quick look at the findings below before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
PERMISSION_DELETE_FILES NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST SECRETS_PATH_DOTENV OBFUSCATION_FILE_CAP_REACHED
Why this grade
- PERMISSION_DELETE_FILES Low
Contains a call that can delete files.
scripts/package-agency.py, line 103
result = subprocess.run(arguments, cwd=root, capture_output=True, text=True) - NETWORK_NO_FIXED_HOST Low
Makes a network call whose host is not written as a fixed address.
cloudflare/src/index.js, line 648
async fetch(request, env, ctx) { - NETWORK_UNNAMED_HOST Low
Calls a fixed host that the description does not name.
cloudflare/src/index.js, line 648
async fetch(request, env, ctx) { - SECRETS_PATH_DOTENV Low
Mentions a .env file.
scripts/audit-public-package.mjs, line 11
const credentialFilePattern = /(^|\/)(?:\.env(?:\..+)?|\.dev\.vars(?:\..+)?|GoogleSer - OBFUSCATION_FILE_CAP_REACHED Note
The 400 file cap was reached before every file was read.
skills/install-jdk-gradle/SKILL.md, line 1
---
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
scripts/package-agency.py, line 103
result = subprocess.run(arguments, cwd=root, capture_output=True, text=True)
scripts/package-agency.py, line 120
subprocess.run(arguments, cwd=ROOT, check=True)
scripts/package-agency.py, line 141
subprocess.run(['node', str(ROOT / 'scripts/check-anthropic-package.mjs'), str(native_root), '--report', str(staged / 'component-inventory.json')], cwd=ROOT, check=True)
Show more
scripts/package-agency.py, line 142
subprocess.run(['node', str(ROOT / 'scripts/validate-anthropic-media.mjs'), str(native_root)], cwd=ROOT, check=True)
scripts/package-agency.py, line 143
subprocess.run(['node', str(ROOT / 'scripts/audit-public-package.mjs'), str(native_root)], cwd=ROOT, check=True)
scripts/package-agency.py, line 146
subprocess.run(['node', 'scripts/validate-openai-upload.mjs', str(staged / f'mobile-app-builder-{version}-openai.zip')], cwd=ROOT, check=True)
scripts/validate-openai-upload.mjs, line 482
fs.rmSync(temporaryRoot, { recursive: true, force: true });
scripts/validate-openai-upload.mjs, line 493
fs.rmSync(temporaryRoot, { recursive: true, force: true });
scripts/validate-openai-upload.mjs, line 508
fs.rmSync(extracted.temporaryRoot, { recursive: true, force: true });
Install and update
Pass
No install-time script found, and dependencies are pinned or absent.
Network
Concern
can reach a host that is not written as a fixed address. can reach exp.host. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
cloudflare/src/index.js, line 648
async fetch(request, env, ctx) {
scripts/verify-public-mcp.mjs, line 55
const response = await fetch(url, {
skills/account-deletion-flow/SKILL.md, line 41
await fetch('/api/account/delete', {
Show more
skills/account-deletion-flow-android/SKILL.md, line 33
await fetch('/api/delete-account', {
skills/add-expo-notifications/SKILL.md, line 66
await fetch('/api/register-push', { method: 'POST', body: JSON.stringify({ token }) });
skills/add-expo-notifications-fcm/SKILL.md, line 89
fetch('https://exp.host/--/api/v2/push/send', {
skills/add-tanstack-query/SKILL.md, line 48
queryFn: async () => fetch('/api/posts').then(r => r.json()),
skills/add-tanstack-query/SKILL.md, line 62
mutationFn: (postId: string) => fetch(`/api/posts/${postId}/like`, { method: 'POST' }),
Secrets
Concern
reads a credential or environment file.
SECRETS_PATH_DOTENV
scripts/audit-public-package.mjs, line 11
const credentialFilePattern = /(^|\/)(?:\.env(?:\..+)?|\.dev\.vars(?:\..+)?|GoogleSer
scripts/audit-public-package.mjs, line 26
const safeValuePattern = /^(?:<[^>]+>|\$\{[^}]+\}|\$[A-Z_][A-Z0-9_]*|process\.env\.|YOUR_|REPLACE_|EXAMPLE_|redacted|placeholder)/i;
scripts/check-anthropic-package.mjs, line 77
if (entry.name.startsWith('.env') || entry.name.startsWith('.dev.vars')
Show more
scripts/package-agency.py, line 54
if file.name.startswith(('.env', '.dev.vars')) or file.name in {'.ssh'
scripts/plan-expo-project.mjs, line 33
"Do not put provider credentials, signing files, or .env values in the project.",
skills/command-scaffold-app/scripts/plan-expo-project.mjs, line 33
"Do not put provider credentials, signing files, or .env values in the project.",
.gitignore, line 1
# Local environment and credentials
.gitignore, line 2
.env
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Note
the file cap was reached before every file was read.
OBFUSCATION_FILE_CAP_REACHED
skills/install-jdk-gradle/SKILL.md, line 1
---
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 3b1834833207. can delete files. can reach a host that is not written as a fixed address. can reach exp.host. The description does not name that host. reads a credential or environment file. the file cap was reached before every file was read.
Date and source
Date checked:
github.com
Commit graded: 3b1834833207216d8b15f98cbc04b47b3a2a2981
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.