capacitor-security by cap-go/capgo-skills
npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-security适用于 Capacitor 和 Ionic 应用的零配置安全扫描。
# 扫描当前目录(无需安装)
npx capsec scan
# 扫描指定路径
npx capsec scan ./my-app
# CI 模式(发现高/严重问题时退出码为 1)
npx capsec scan --ci
# CLI 输出(默认)
npx capsec scan
# JSON 报告
npx capsec scan --output json --output-file report.json
# HTML 报告
npx capsec scan --output html --output-file security-report.html
# 仅显示严重和高等级别的问题
npx capsec scan --severity high
# 指定类别
npx capsec scan --categories secrets,network,storage
# 排除测试文件
npx capsec scan --exclude "**/test/**,**/*.spec.ts"
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 规则 | 严重性 | 描述 |
|---|
| SEC001 | 严重 | 硬编码的 API 密钥和密钥 |
| SEC002 | 高 | 暴露的 .env 文件 |
Capsec 检测内容 :
修复示例 :
// 错误 - 硬编码的 API 密钥
const API_KEY = 'sk_live_abc123xyz';
// 正确 - 使用环境变量
import { Env } from '@capgo/capacitor-env';
const API_KEY = await Env.get({ key: 'API_KEY' });
| 规则 | 严重性 | 描述 |
|---|---|---|
| STO001 | 高 | 偏好设置中存储未加密的敏感数据 |
| STO002 | 高 | 使用 localStorage 存储敏感数据 |
| STO003 | 中 | SQLite 数据库未加密 |
| STO004 | 中 | 文件系统存储敏感数据 |
| STO005 | 低 | 不安全的数据缓存 |
| STO006 | 高 | 未使用 Keychain/Keystore 存储凭据 |
修复示例 :
// 错误 - 明文存储令牌到偏好设置
import { Preferences } from '@capacitor/preferences';
await Preferences.set({ key: 'auth_token', value: token });
// 正确 - 使用安全存储
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
await NativeBiometric.setCredentials({
username: email,
password: token,
server: 'api.myapp.com',
});
| 规则 | 严重性 | 描述 |
|---|---|---|
| NET001 | 严重 | HTTP 明文传输 |
| NET002 | 高 | 缺少 SSL/TLS 证书固定 |
| NET003 | 高 | 启用了 Capacitor 服务器明文传输 |
| NET004 | 中 | 不安全的 WebSocket 连接 |
| NET005 | 中 | CORS 通配符配置 |
| NET006 | 中 | 不安全的深度链接验证 |
| NET007 | 低 | Capacitor HTTP 插件误用 |
| NET008 | 高 | URL 参数中包含敏感数据 |
修复示例 :
// 错误 - 生产环境使用 HTTP
const config: CapacitorConfig = {
server: {
cleartext: true, // 生产环境绝不允许!
},
};
// 正确 - 仅使用 HTTPS
const config: CapacitorConfig = {
server: {
cleartext: false,
// 仅允许特定域名
allowNavigation: ['https://api.myapp.com'],
},
};
| 规则 | 严重性 | 描述 |
|---|---|---|
| CAP001 | 高 | 启用了 WebView 调试模式 |
| CAP002 | 中 | 不安全的插件配置 |
| CAP003 | 低 | 生产环境中的详细日志记录 |
| CAP004 | 高 | 不安全的 allowNavigation |
| CAP005 | 严重 | 原生桥暴露 |
| CAP006 | 严重 | 使用用户输入的 Eval |
| CAP007 | 中 | 缺少 Root/越狱检测 |
| CAP008 | 低 | 不安全的插件导入 |
| CAP009 | 中 | 实时更新安全 |
| CAP010 | 高 | 不安全的 postMessage 处理器 |
修复示例 :
// 错误 - 生产环境启用调试模式
const config: CapacitorConfig = {
ios: {
webContentsDebuggingEnabled: true, // 生产环境移除!
},
android: {
webContentsDebuggingEnabled: true, // 生产环境移除!
},
};
// 正确 - 仅在开发环境启用
const config: CapacitorConfig = {
ios: {
webContentsDebuggingEnabled: process.env.NODE_ENV === 'development',
},
};
| 规则 | 严重性 | 描述 |
|---|---|---|
| AND001 | 高 | 允许 Android 明文传输 |
| AND002 | 中 | 启用了 Android 调试模式 |
| AND003 | 中 | 不安全的 Android 权限 |
| AND004 | 低 | 允许 Android 备份 |
| AND005 | 高 | 导出的组件无权限控制 |
| AND006 | 中 | 启用 WebView JavaScript 但无安全措施 |
| AND007 | 严重 | 不安全的 WebView addJavascriptInterface |
| AND008 | 严重 | 硬编码的签名密钥 |
修复 AndroidManifest.xml :
<!-- 错误 -->
<application android:usesCleartextTraffic="true">
<!-- 正确 -->
<application
android:usesCleartextTraffic="false"
android:allowBackup="false"
android:networkSecurityConfig="@xml/network_security_config">
network_security_config.xml :
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.myapp.com</domain>
<pin-set>
<pin digest="SHA-256">your-pin-hash</pin>
</pin-set>
</domain-config>
</network-security-config>
| 规则 | 严重性 | 描述 |
|---|---|---|
| IOS001 | 高 | 应用传输安全被禁用 |
| IOS002 | 中 | 不安全的 Keychain 访问 |
| IOS003 | 中 | URL Scheme 无验证 |
| IOS004 | 低 | iOS 剪贴板敏感数据 |
| IOS005 | 中 | 不安全的 iOS 权利 |
| IOS006 | 低 | 后台应用刷新数据暴露 |
| IOS007 | 中 | 缺少 iOS 越狱检测 |
| IOS008 | 低 | 敏感屏幕未禁用截图 |
修复 Info.plist :
<!-- 错误 - 禁用 ATS -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<!-- 正确 - 仅特定例外 -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>legacy-api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
</dict>
</dict>
</dict>
| 规则 | 严重性 | 描述 |
|---|---|---|
| AUTH001 | 严重 | 弱 JWT 验证 |
| AUTH002 | 高 | 不安全的生物识别实现 |
| AUTH003 | 高 | 弱随机数生成 |
| AUTH004 | 中 | 缺少会话超时 |
| AUTH005 | 高 | 缺少 OAuth 状态参数 |
| AUTH006 | 严重 | 认证中硬编码凭据 |
修复示例 :
// 错误 - 无 JWT 验证
const decoded = jwt.decode(token);
// 正确 - 验证 JWT 签名
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.myapp.com',
audience: 'myapp',
});
| 规则 | 严重性 | 描述 |
|---|---|---|
| WEB001 | 严重 | WebView JavaScript 注入 |
| WEB002 | 中 | 不安全的 iframe 配置 |
| WEB003 | 中 | 外部脚本加载 |
| WEB004 | 中 | 缺少内容安全策略 |
| WEB005 | 低 | 使用 target _blank 但无 noopener |
修复 - 添加 CSP :
<!-- index.html -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.myapp.com;
font-src 'self';
frame-ancestors 'none';
">
| 规则 | 严重性 | 描述 |
|---|---|---|
| CRY001 | 严重 | 弱加密算法 |
| CRY002 | 严重 | 硬编码的加密密钥 |
| CRY003 | 高 | 不安全的随机 IV 生成 |
| CRY004 | 高 | 弱密码哈希 |
修复示例 :
// 错误 - 弱算法
const encrypted = CryptoJS.DES.encrypt(data, key);
// 正确 - 强算法
const encrypted = CryptoJS.AES.encrypt(data, key, {
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.Pkcs7,
});
// 错误 - 硬编码密钥
const key = 'my-secret-key-123';
// 正确 - 派生密钥
const key = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
| 规则 | 严重性 | 描述 |
|---|---|---|
| LOG001 | 高 | 控制台日志中包含敏感数据 |
| LOG002 | 低 | 生产环境中的控制台日志 |
修复示例 :
// 错误 - 记录敏感数据
console.log('User password:', password);
console.log('Token:', authToken);
// 正确 - 脱敏敏感数据
console.log('User authenticated:', userId);
// 使用条件日志记录
if (process.env.NODE_ENV === 'development') {
console.debug('Debug info:', data);
}
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Run Capsec Security Scan
run: npx capsec scan --ci --output json --output-file security-report.json
- name: Upload Security Report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report
path: security-report.json
security-scan:
image: node:20
script:
- npx capsec scan --ci
artifacts:
reports:
security: security-report.json
only:
- merge_requests
- main
{
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/*.test.ts",
"**/*.spec.ts"
],
"severity": "low",
"categories": [],
"rules": {
"LOG002": {
"enabled": false
},
"SEC001": {
"severity": "critical"
}
}
}
npx capsec init
import { IsRoot } from '@capgo/capacitor-is-root';
async function checkDeviceSecurity() {
const { isRooted } = await IsRoot.isRooted();
if (isRooted) {
// 选项 1: 警告用户
showWarning('Device security compromised');
// 选项 2: 限制功能
disableSensitiveFeatures();
// 选项 3: 阻止应用(针对高安全应用)
blockApp();
}
}
npx capsec scan --severity high每周安装量
101
代码仓库
GitHub 星标数
20
首次出现
2026年2月6日
安全审计
安装于
gemini-cli98
opencode96
github-copilot94
codex94
kimi-cli92
amp92
Zero-config security scanning for Capacitor and Ionic apps.
# Scan current directory (no installation needed)
npx capsec scan
# Scan specific path
npx capsec scan ./my-app
# CI mode (exit code 1 on high/critical issues)
npx capsec scan --ci
# CLI output (default)
npx capsec scan
# JSON report
npx capsec scan --output json --output-file report.json
# HTML report
npx capsec scan --output html --output-file security-report.html
# Only critical and high severity
npx capsec scan --severity high
# Specific categories
npx capsec scan --categories secrets,network,storage
# Exclude test files
npx capsec scan --exclude "**/test/**,**/*.spec.ts"
| Rule | Severity | Description |
|---|---|---|
| SEC001 | Critical | Hardcoded API Keys & Secrets |
| SEC002 | High | Exposed .env File |
What Capsec Detects :
Fix Example :
// BAD - Hardcoded API key
const API_KEY = 'sk_live_abc123xyz';
// GOOD - Use environment variables
import { Env } from '@capgo/capacitor-env';
const API_KEY = await Env.get({ key: 'API_KEY' });
| Rule | Severity | Description |
|---|---|---|
| STO001 | High | Unencrypted Sensitive Data in Preferences |
| STO002 | High | localStorage Usage for Sensitive Data |
| STO003 | Medium | SQLite Database Without Encryption |
| STO004 | Medium | Filesystem Storage of Sensitive Data |
| STO005 | Low | Insecure Data Caching |
| STO006 | High | Keychain/Keystore Not Used for Credentials |
Fix Example :
// BAD - Plain preferences for tokens
import { Preferences } from '@capacitor/preferences';
await Preferences.set({ key: 'auth_token', value: token });
// GOOD - Use secure storage
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
await NativeBiometric.setCredentials({
username: email,
password: token,
server: 'api.myapp.com',
});
| Rule | Severity | Description |
|---|---|---|
| NET001 | Critical | HTTP Cleartext Traffic |
| NET002 | High | SSL/TLS Certificate Pinning Missing |
| NET003 | High | Capacitor Server Cleartext Enabled |
| NET004 | Medium | Insecure WebSocket Connection |
| NET005 | Medium | CORS Wildcard Configuration |
| NET006 | Medium | Insecure Deep Link Validation |
| NET007 | Low | Capacitor HTTP Plugin Misuse |
| NET008 | High | Sensitive Data in URL Parameters |
Fix Example :
// BAD - HTTP in production
const config: CapacitorConfig = {
server: {
cleartext: true, // Never in production!
},
};
// GOOD - HTTPS only
const config: CapacitorConfig = {
server: {
cleartext: false,
// Only allow specific domains
allowNavigation: ['https://api.myapp.com'],
},
};
| Rule | Severity | Description |
|---|---|---|
| CAP001 | High | WebView Debug Mode Enabled |
| CAP002 | Medium | Insecure Plugin Configuration |
| CAP003 | Low | Verbose Logging in Production |
| CAP004 | High | Insecure allowNavigation |
| CAP005 | Critical | Native Bridge Exposure |
| CAP006 | Critical | Eval Usage with User Input |
| CAP007 | Medium | Missing Root/Jailbreak Detection |
| CAP008 | Low | Insecure Plugin Import |
| CAP009 | Medium | Live Update Security |
| CAP010 | High |
Fix Example :
// BAD - Debug mode in production
const config: CapacitorConfig = {
ios: {
webContentsDebuggingEnabled: true, // Remove in production!
},
android: {
webContentsDebuggingEnabled: true, // Remove in production!
},
};
// GOOD - Only in development
const config: CapacitorConfig = {
ios: {
webContentsDebuggingEnabled: process.env.NODE_ENV === 'development',
},
};
| Rule | Severity | Description |
|---|---|---|
| AND001 | High | Android Cleartext Traffic Allowed |
| AND002 | Medium | Android Debug Mode Enabled |
| AND003 | Medium | Insecure Android Permissions |
| AND004 | Low | Android Backup Allowed |
| AND005 | High | Exported Components Without Permission |
| AND006 | Medium | WebView JavaScript Enabled Without Safeguards |
| AND007 | Critical | Insecure WebView addJavascriptInterface |
| AND008 | Critical | Hardcoded Signing Key |
Fix AndroidManifest.xml :
<!-- BAD -->
<application android:usesCleartextTraffic="true">
<!-- GOOD -->
<application
android:usesCleartextTraffic="false"
android:allowBackup="false"
android:networkSecurityConfig="@xml/network_security_config">
network_security_config.xml :
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.myapp.com</domain>
<pin-set>
<pin digest="SHA-256">your-pin-hash</pin>
</pin-set>
</domain-config>
</network-security-config>
| Rule | Severity | Description |
|---|---|---|
| IOS001 | High | App Transport Security Disabled |
| IOS002 | Medium | Insecure Keychain Access |
| IOS003 | Medium | URL Scheme Without Validation |
| IOS004 | Low | iOS Pasteboard Sensitive Data |
| IOS005 | Medium | Insecure iOS Entitlements |
| IOS006 | Low | Background App Refresh Data Exposure |
| IOS007 | Medium | Missing iOS Jailbreak Detection |
| IOS008 | Low | Screenshots Not Disabled for Sensitive Screens |
Fix Info.plist :
<!-- BAD - Disables ATS -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<!-- GOOD - Specific exceptions only -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>legacy-api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
</dict>
</dict>
</dict>
| Rule | Severity | Description |
|---|---|---|
| AUTH001 | Critical | Weak JWT Validation |
| AUTH002 | High | Insecure Biometric Implementation |
| AUTH003 | High | Weak Random Number Generation |
| AUTH004 | Medium | Missing Session Timeout |
| AUTH005 | High | OAuth State Parameter Missing |
| AUTH006 | Critical | Hardcoded Credentials in Auth |
Fix Example :
// BAD - No JWT validation
const decoded = jwt.decode(token);
// GOOD - Verify JWT signature
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.myapp.com',
audience: 'myapp',
});
| Rule | Severity | Description |
|---|---|---|
| WEB001 | Critical | WebView JavaScript Injection |
| WEB002 | Medium | Unsafe iframe Configuration |
| WEB003 | Medium | External Script Loading |
| WEB004 | Medium | Content Security Policy Missing |
| WEB005 | Low | Target _blank Without noopener |
Fix - Add CSP :
<!-- index.html -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.myapp.com;
font-src 'self';
frame-ancestors 'none';
">
| Rule | Severity | Description |
|---|---|---|
| CRY001 | Critical | Weak Cryptographic Algorithm |
| CRY002 | Critical | Hardcoded Encryption Key |
| CRY003 | High | Insecure Random IV Generation |
| CRY004 | High | Weak Password Hashing |
Fix Example :
// BAD - Weak algorithm
const encrypted = CryptoJS.DES.encrypt(data, key);
// GOOD - Strong algorithm
const encrypted = CryptoJS.AES.encrypt(data, key, {
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.Pkcs7,
});
// BAD - Hardcoded key
const key = 'my-secret-key-123';
// GOOD - Derived key
const key = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
| Rule | Severity | Description |
|---|---|---|
| LOG001 | High | Sensitive Data in Console Logs |
| LOG002 | Low | Console Logs in Production |
Fix Example :
// BAD - Logging sensitive data
console.log('User password:', password);
console.log('Token:', authToken);
// GOOD - Redact sensitive data
console.log('User authenticated:', userId);
// Use conditional logging
if (process.env.NODE_ENV === 'development') {
console.debug('Debug info:', data);
}
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Run Capsec Security Scan
run: npx capsec scan --ci --output json --output-file security-report.json
- name: Upload Security Report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report
path: security-report.json
security-scan:
image: node:20
script:
- npx capsec scan --ci
artifacts:
reports:
security: security-report.json
only:
- merge_requests
- main
{
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/*.test.ts",
"**/*.spec.ts"
],
"severity": "low",
"categories": [],
"rules": {
"LOG002": {
"enabled": false
},
"SEC001": {
"severity": "critical"
}
}
}
npx capsec init
import { IsRoot } from '@capgo/capacitor-is-root';
async function checkDeviceSecurity() {
const { isRooted } = await IsRoot.isRooted();
if (isRooted) {
// Option 1: Warn user
showWarning('Device security compromised');
// Option 2: Restrict features
disableSensitiveFeatures();
// Option 3: Block app (for high-security apps)
blockApp();
}
}
npx capsec scan --severity highWeekly Installs
101
Repository
GitHub Stars
20
First Seen
Feb 6, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli98
opencode96
github-copilot94
codex94
kimi-cli92
amp92
Lark Mail CLI 使用指南:邮件管理、安全规则与自动化工作流
37,000 周安装
| Insecure postMessage Handler |