A zero-configuration security scanner for React Native and Expo applications that detects vulnerabilities, hardcoded secrets, and security misconfigurations with a single command.
npm install -g rnsec
npx rnsec scan
git clone https://github.com/adnxy/rnsec.git
cd rnsec
npm install
npm run build
npm link
Scan your React Native or Expo project:
rnsec scan
View the generated HTML report:
open rnsec-report.html
That's it. No configuration needed.
Scan current directory:
rnsec scan
HTML Report:
Scan specific project:
rnsec scan --path ./my-app
Custom output filenames:
rnsec scan --html security-report.html --output results.json
CI/CD mode (silent, JSON only):
rnsec scan --silent --output results.json
Console JSON output (no files):
rnsec scan --json
View all security rules:
rnsec rules
Scan only changed files:
rnsec scan --changed-files main
rnsec scan --changed-files abc123
rnsec scan --changed-files ${{ github.base_ref }}
rnsec scan [options]
Options:
-p, --path <path> Project directory to scan (default: current directory)
--html <filename> Custom HTML report filename
--output <filename> Custom JSON report filename
--md <filename> Generate Markdown report for PR comments
--json Output JSON to console only (no files)
--silent Suppress console output
--changed-files <ref> Scan only files changed since git reference (branch, commit, or tag)
-h, --help Display help information
-V, --version Display version number
0 - No high-severity issues found1 - High-severity security issues detectedThe --changed-files option allows you to scan only files that have changed since a specific git reference, making it perfect for CI/CD pipelines and pull request validation.
# Scan files changed since main branch
rnsec scan --changed-files main
# Scan files changed since specific commit
rnsec scan --changed-files abc123def456
# Scan files changed since a tag
rnsec scan --changed-files v1.2.0
# Use in CI/CD with JSON output
rnsec scan --changed-files main --output security.json --silent
The --changed-files option accepts any valid git reference:
main, develop, feature/new-authabc123def456, HEAD~1v1.0.0, release-2024HEAD, origin/mainGitHub Actions:
- name: Run security scan on PR changes
run: rnsec scan --changed-files ${{ github.base_ref }} --output security.json --silent
GitLab CI:
security-scan:
script:
- rnsec scan --changed-files $CI_MERGE_REQUEST_TARGET_BRANCH_NAME --output security.json --silent
Generate markdown reports that can be automatically posted as GitHub PR comments, bringing security results directly into your pull requests with advanced features like automatic comment updates, comparison tracking, and security metrics.
# Generate markdown report for PR comment
rnsec scan --md security-report.md --silent
# Combine with changed files for PR-focused scanning
rnsec scan --changed-files main --md pr-security-report.md --silent
Copy the example workflow from examples/github-actions/security-scan.yml:
name: 🔒 Security Scan
on:
pull_request:
branches: [ main, develop ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install rnsec
run: npm install -g rnsec
- name: Run security scan
run: |
rnsec scan --changed-files ${{ github.base_ref || 'main' }} --md security-report.md --output rnsec-report.json --silent
continue-on-error: true
- name: Comment PR with security results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const markdownReport = fs.readFileSync('security-report.md', 'utf8');
const commentIdentifier = '';
// Find and update existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existingComment = comments.find(c => c.body?.includes(commentIdentifier));
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body: markdownReport
});
} else {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: markdownReport
});
}
See examples/gitlab-ci/security-scan.yml for GitLab merge request integration.
See examples/bitbucket-pipelines/bitbucket-pipelines.yml for Bitbucket pull request integration.
See examples/azure-devops/azure-pipelines.yml for Azure Pipelines integration.
The enhanced markdown report includes: - Summary table with issue counts by severity - Comparison data showing new/resolved issues since last scan - Security metrics dashboard with score and trends - Collapsible findings organized by severity - Code snippets with syntax highlighting - Risk assessment with clear action items - Performance metrics and scan information
rnsec supports configuration files to customize the scanning behavior. Create a .rnsec.jsonc or .rnsec.json file in your project root.
You can ignore specific rules by adding them to the ignoredRules array:
{
"ignoredRules": [
"ASYNCSTORAGE_SENSITIVE_KEY",
"LOGGING_SENSITIVE_DATA"
]
}
To find the rule ID for a specific finding, check the ruleId field in the JSON output or HTML report.
You can exclude specific files and directories by adding exclude patterns to the exclude array:
{
"exclude": [
"**/scripts/**"
]
}
Any pattern supported by fast-glob can be used, for more information see Pattern syntax.
rnsec identifies 63 different security issues across 13 categories:
Common vulnerabilities found:
// Hardcoded API keys and secrets
const API_KEY = 'your_secret_api_key_here'; // Never commit real keys!
// Insecure data storage
await AsyncStorage.setItem('user_token', token);
// Unencrypted HTTP requests
fetch('http://api.example.com/data');
// Weak cryptographic algorithms
const hash = MD5(password);
// Missing security properties
<TextInput value={password} /> // Missing secureTextEntry
rnsec implements 63 security rules covering:
| Category | Rules | Description |
|---|---|---|
| Storage | 7 | AsyncStorage security, encryption requirements, PII handling, Unencrypted MMKV |
| Network | 13 | HTTP connections, SSL/TLS validation, WebView security |
| Authentication | 6 | JWT handling, OAuth implementation, biometric authentication |
| Secrets | 2 | API key detection (27+ patterns), hardcoded credentials |
| Cryptography | 2 | Weak algorithms, hardcoded encryption keys |
| Logging | 2 | Sensitive data exposure in logs |
| React Native | 10 | Native bridge security, deep links, eval() usage |
| Debug | 3 | Test credentials, development tools in production |
| Android | 8 | Manifest security, Keystore issues, permission checks |
| iOS | 8 | App Transport Security, Keychain usage, Info.plist |
| Config | 1 | Dangerous permission configurations |
| WebView | 1 | WebView injection vulnerabilities |
| Manifest | 1 | Platform-specific manifest issues |
rnsec detects 27+ types of hardcoded API keys and secrets:
rnsec generates two report formats automatically:
rnsec-report.htmlrnsec-report.jsonCreate .github/workflows/security.yml:
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
security:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install rnsec
run: npm install -g rnsec
- name: Run security scan
run: rnsec scan --output security.json --silent
- name: Upload reports
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report
path: |
security.json
rnsec-report.html
```yaml name: Security Scan
on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ]
jobs: security_scan: type: build params: platform: android steps: - name: Security validation only run: | echo "🔒 Running security validation..." echo "Current directory: $(pwd)" echo "Contents:" ls -la
# Look for project in current and parent directories
echo "🔍 Searching for project..."
# Check current directory first
if [ -f "package.json" ]; then
PROJECT_DIR="."
else
# Check parent directory
if [ -f "../package.json" ]; then
PROJECT_DIR=".."
else
# Search recursively
PROJECT_DIR=$(find .. -name "package.json" -type f -printf '%h' | head -1)
fi
fi
if [ -z "$PROJECT_DIR" ] || [ ! -f "$PROJECT_DIR/package.json" ]; then
echo "❌ No package.json found in any location"
echo "📁 Searching all directories:"
find .. -name "package.json" -type f 2>/dev/null || echo "No package.json found anywhere"
exit 1
fi
echo "✅ Found project at: $PROJECT_DIR"
cd
$ claude mcp add rnsec \
-- python -m otcore.mcp_server <graph>