mcpField
C
capacitor-security

capacitor-security

github.com/cap-goSecurity731.2k installsUpdated 2w ago
Repository

About capacitor-security

A skill for auditing and hardening the security of Capacitor app layers, aimed at developers investigating mobile security risks or pentest findings. It combines scanner guidance with Capacitor-specific checks for bundles, storage, networking, WebViews, bridges, and native configuration.

Key features

  1. 01Capgo scanner setup and result triage
  2. 02Bundle secret and storage checks
  3. 03Network and certificate guidance
  4. 04WebView and native bridge review
  5. 05Android and iOS manifest hardening

Use cases

  1. 01Reviewing an app against mobile security findings
  2. 02Checking built assets for exposed credentials
  3. 03Securing token storage and network transport
  4. 04Auditing bridge access and platform settings

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-security

After installing, type/capacitor-securityin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

metadata.json
references/
capsec-scanner.md
network.md
platform-hardening.md
secrets-and-storage.md
webview-and-bridge.md

Details

From the project README

Capacitor Security

Audit and harden the app layer of a Capacitor app: secrets in the bundle, on-device storage, network transport, WebView and native bridge exposure, and platform manifests.

When to Use

TRIGGER when:

  • The user asks for a security audit, OWASP Mobile Top 10 / MASVS review, or wants to fix pentest findings.
  • The user wants to run or interpret @capgo/capgo-sec (capsec) results, rule IDs such as SEC001, STO002, NET003, CAP004, AND004, IOS001.
  • API keys, service-role keys, or .env values appear in src/, dist/, www/, or capacitor.config.*.
  • Auth tokens are stored with Preferences.set, localStorage, IndexedDB, or plain SQLite.
  • capacitor.config.* contains server.cleartext: true, server.url, broad server.allowNavigation, android.allowMixedContent, or webContentsDebuggingEnabled: true.
  • Native files contain NSAllowsArbitraryLoads, android:usesCleartextTraffic="true", android:allowBackup="true", android:debuggable, or exported components without permissions.
  • The user needs certificate pinning, a Content Security Policy, screenshot protection, or root/jailbreak detection.

Do not use:

  • Xcode build settings, Enhanced Security, pointer authentication, stack/heap hardening -> capacitor-ios-security-hardening.
  • Universal Links / App Links setup -> capacitor-deep-linking (this skill only covers validating incoming URLs).
  • Privacy manifests, App Review rejections -> capacitor-apple-review-preflight; store listing -> capacitor-app-store.
  • Pipeline structure and signing secrets in CI -> capacitor-ci-cd.
  • Live update installation and channels -> capgo-live-updates (this skill covers only bundle encryption).
  • Runtime crashes and WebView inspection -> debugging-capacitor.

Workflow

  1. Inspect before editing. Read capacitor.config.ts|json, package.json (Capacitor major, installed plugins), android/app/src/main/AndroidManifest.xml, android/app/src/main/res/xml/network_security_config.xml (if any), ios/App/App/Info.plist, *.entitlements, and index.html.
  2. Scan. Run the Capgo scanner from the project root (Node 18+):
    npx @capgo/capgo-sec@latest scan --severity medium
    
    The npm package is @capgo/capgo-sec; it installs a capsec binary. npx capsec does not work because no package named capsec exists on npm.
  3. Grep for what scanners miss (see Verification). Build the web app first and also grep dist/ or www/: bundlers inline import.meta.env.* and process.env.* values.
  4. Triage and report before invasive changes. Group findings by Critical/High/Medium/Low with file and line. Ask the user before changes that alter behavior: certificate pinning (can lock out users when certs rotate), blocking rooted devices, removing allowNavigation hosts, a strict CSP.
  5. Fix by area, loading the matching reference below.
  6. Re-run the scan and Verification checks, then npx cap sync and test a release build on a device.

Capacitor-specific traps

  • Nothing in the bundle is secret. Web assets ship inside the IPA/APK and capacitor.config.json is copied into native assets. Values in plugins.* config (including @capgo/capacitor-env) are extractable. Move secret-bearing calls to a backend.
  • allowNavigation grants bridge access. On Android, every allowNavigation entry is added to the bridge's allowed origin rules, so pages from those hosts can call your native plugins. Only list hosts you control. Open third-party pages with @capacitor/browser or @capgo/inappbrowser instead.
  • server.url and server.cleartext are dev-only. Capacitor documents both as "not intended for use in production." A committed LAN IP ships a WebView that loads remote code over HTTP.
  • Debuggable WebView in release. ios.webContentsDebuggingEnabled / android.webContentsDebuggingEnabled default to on only in debug builds. A hardcoded true exposes the WebView to Safari / chrome://inspect on any release build.
  • CapacitorHttp is not pinning. plugins.CapacitorHttp.enabled only routes fetch/XHR through native networking. Pinning requires @capgo/capacitor-ssl-pinning, which hooks into CapacitorHttp.
  • Biometric prompt is not authentication. verifyIdentity() can be hooked on rooted/jailbroken devices. Keep secrets behind accessControl (hardware-bound Keychain/Keystore item) and validate sessions server-side.
  • OAuth via custom schemes needs PKCE. Any app can register myapp://. Use PKCE and prefer Universal/App Links for redirects.
  • Live update bundles are public unless encrypted. Private channels limit who receives a bundle. They do not make it confidential.

References

Only load a reference when its topic is in play.

ReferenceLoad when
references/capsec-scanner.mdRunning the scanner, reading rule IDs, CI gating, JSON/HTML reports
references/secrets-and-storage.mdHardcoded keys, .env leakage, token storage, Keychain/Keystore, encrypted SQLite, logging
references/network.mdHTTPS/ATS/cleartext, network_security_config.xml, certificate pinning, CORS vs CapacitorHttp
references/webview-and-bridge.mdCSP, allowNavigation, iframes, postMessage, eval, deep link/OAuth validation
references/platform-hardening.mdAndroidManifest flags, R8, iOS Info.plist/entitlements, screenshot protection, root/jailbreak detection, live update encryption

Xcode compiler/linker hardening is not covered here: use capacitor-ios-security-hardening.

Verification

Run from the project root. Each grep should return nothing for a release build, or only intentional, documented hits.

# 1. Scanner gate (exit code 1 on high/critical)
npx @capgo/capgo-sec@latest scan --ci

# 2. Dev-only config left in capacitor.config
grep -nE "cleartext|server:\s*\{|\"url\"|url:|allowMixedContent|webContentsDebuggingEnabled" capacitor.config.* 

# 3. Secrets in the built bundle (build first)
npm run build
grep -rnE "sk_live_|sk-ant-|sk-proj-|AKIA[0-9A-Z]{16}|service_role|-----BEGIN (RSA |EC )?PRIVATE KEY" dist/ www/ 2>/dev/null

# 4. Tokens in plain storage
grep -rnE "(Preferences\.set|localStorage\.setItem)\(.*(token|password|secret|jwt)" -i src/

# 5. Android manifest flags
grep -nE "usesCleartextTraffic|allowBackup|debuggable|exported=\"true\"" android/app/src/main/AndroidManifest.xml

# 6. iOS transport and file sharing
plutil -p ios/App/App/Info.plist | grep -E "NSAllowsArbitraryLoads|NSExceptionAllowsInsecureHTTPLoads|UIFileSharingEnabled|LSSupportsOpeningDocumentsInPlace"

# 7. Native projects pick up config changes
npx cap sync

Then install a release build on a device and confirm: login works, API calls succeed (pinning did not break them), Safari Web Inspector / chrome://inspect cannot attach.

Error handling

ErrorCauseFix
net::ERR_CLEARTEXT_NOT_PERMITTED (Android)HTTP request blocked; cleartext is off by default since API 28Use HTTPS. For dev live reload only, use server.cleartext: true in a dev-only config. Never ship usesCleartextTraffic="true".
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. (iOS, NSURLError -1022)HTTP URL under ATSUse HTTPS. If a legacy host is unavoidable, add a narrow NSExceptionDomains entry, never NSAllowsArbitraryLoads.
... has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is presentBackend does not allow the WebView originAllow capacitor://localhost (iOS) and https://localhost (Android default) on the server, or enable CapacitorHttp. Do not add Access-Control-Allow-Origin: * to authenticated endpoints.
Refused to connect to '<url>' because it violates the following Content Security Policy directiveCSP connect-src missing a hostAdd the exact API origin to connect-src. Do not fall back to *.
Pinned requests fail after a certificate renewalPin matched only the old leaf certPin the CA or intermediate plus a backup cert; ship the backup before rotating.
npm error 404 Not Found - GET https://registry.npmjs.org/capsecWrong package nameUse npx @capgo/capgo-sec@latest scan.
No protected credentials found / No protected data found (code 21, @capgo/capacitor-native-biometric)Nothing stored with accessControl, fresh install, or the item was invalidated by a biometric enrollment changeTreat as "logged out": re-authenticate against the server, then store again with AccessControl.BIOMETRY_CURRENT_SET or BIOMETRY_ANY.

Resources

Comments

Markdown supported