Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies.

MITAuto-check: notesSecurity

Install Static Security

skills CLI
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/static-security .claude/skills/static-security && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
static-security
GitHub stars
169
Token cost
~4.4k tokens
SKILL.md length
1,470 words
Files
6 (incl. references)
Skills in repo
15
Repo updated
First seen
Licence
MIT

At a glance

Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies.

  • Writing code handling secrets
  • SKILL.md covers Core Standards, Severity Triage, Secrets & API Keys and Secure Data Storage, plus 7 more sections
  • Calls dart and adb; needs API_KEY
  • Network communication

What it does

Static Security is an agent skill from VeryGoodOpenSource/vgv-ai-flutter-plugin. Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies. Use when reviewing or writing code handling secrets, user data, network communication, authentication, or cryptography, or adding validation to user input in login, sign-up, or payment forms before it reaches a repository or an API. Also when asked to implement the insecure change rather than review it: moving an API key to --dart-define…

Its SKILL.md is about 4.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 7 other files, including reference files (for example `agents/openai.yaml`, `references/binary-protection.md` and `references/crypto.md`).

It sits in Security, covering Vulnerability scanning, Cross-platform mobile apps and Security review. It works with Dart and Flutter. The repository describes itself as: AI plugin to enhance and accelerate Flutter & Dart development, built by Very Good Ventures. The licence is MIT.

When your agent uses it

  • Writing code handling secrets
  • Network communication
  • Adding validation to user input in login
  • Payment forms before it reaches a repository

Example prompts

  • “our reviewer flagged this line”
  • “security”
  • “/static-security”

Requirements

  • A credential in API_KEY
  • Pre-approved tools (allowed-tools): Read, Glob, Grep, mcp__very-good-cli__packages_check_licenses

What it can do on your machine

Read from SKILL.md and the folder at commit 496a3c6. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Glob
    • Grep
    • mcp__very-good-cli__packages_check_licenses

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • dart
    • adb

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • engineering.verygood.ventures
    • owasp.org

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • API_KEY

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Static Security loads about 4.4k tokens when it runs, and up to ~6k if it reads all its reference files. Until then it costs about 213 tokens; SKILL.md has 1,470 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~213
When it runs · the whole SKILL.md, loaded when a task matches
~4.4k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NoteMentions a .env fileSKILL.md:9
    --dart-define, String.fromEnvironment, a .env file, or CI
  • NoteMentions a .env fileSKILL.md:28
    neither is `String.fromEnvironment`, a `.env` file, a native config file, an obfuscated constant, or a split-up string.
  • NoteMentions a .env fileSKILL.md:56
    t source files, `google-services.json`, `.env`, `*.plist`, `AndroidManifest.xml`, `Info.plist`.
  • NoteMentions a .env fileSKILL.md:84
    | `.env` bundled as an asset                 | Ships in the app bundle, readable after unzipping it  |
  • NoteMentions a .env fileSKILL.md:89
    ime API key into a client. Never commit `.env` files or files containing real credentials to version control: exclude th

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from VeryGoodOpenSource/vgv-ai-flutter-plugin at commit 496a3c6, republished under its MIT licence (© VeryGoodOpenSource). 1,470 words, ~4,438 tokens.

Download SKILL.mdSave it as .claude/skills/static-security/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
static-security
description
Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies. Use when reviewing or writing code handling secrets, user data, network communication, authentication, or cryptography, or adding validation to user input in login, sign-up, or payment forms before it reaches a repository or an API. Also when asked to implement the insecure change rather than review it: moving an API key to --dart-define, String.fromEnvironment, a .env file, or CI secrets, or "our reviewer flagged this line". Also for dependency vulnerability review and security audits that never say "security": whether a pubspec is safe to release, checking dependencies for known vulnerabilities or CVEs, an ignored_advisories entry, or pinned versions we're exposed to.
allowed-tools
Read, Glob, Grep, mcp__very-good-cli__packages_check_licenses
argument-hint
[file-or-directory]
effort
high

Security

Flutter apps compile all Dart code directly into a binary that runs on untrusted devices. This skill covers static security review for Flutter/Dart codebases, anchored to the VGV Security in Mobile Apps guide and the OWASP Mobile Top 10. Every finding in this skill is something detectable by reading source code — no pen-testing or runtime analysis.

Core Standards

Apply these standards to all Flutter security work:

  • Never hardcode secrets — API keys, tokens, and passwords in source code or config files are compiled into the binary and extractable via reverse engineering; serve them from a backend service
  • --dart-define is not a fix for a hardcoded secret — neither is String.fromEnvironment, a .env file, a native config file, an obfuscated constant, or a split-up string. Every one of them still ships the value inside the binary in recoverable form, so moving a key into one is the same finding in a new location. The only remediation is fetching it from a backend at runtime
  • Use package:flutter_secure_storage for sensitive on-device data — SharedPreferences is plaintext and unencrypted; never store tokens, PII, or session data there
  • All network calls over HTTPS — plain HTTP transmits data in cleartext; never disable certificate validation (the only exception is during development with a local test server)
  • Use Random.secure() for security-sensitive randomness — dart:math's Random() is a pseudo-random number generator, not cryptographically secure
  • Use established crypto packages — never implement custom cryptography; use package:crypto or package:dart_crypt
  • Enforce auth at the repository layer — widget-only auth checks are client-side and bypassable by anyone with access to the device
  • No sensitive data in logs — print(), log(), and debugPrint() output is readable on-device and in crash reporting tools
  • Keep dependencies free of known vulnerabilities — never suppress security advisories without documented justification; scan pubspec.lock with osv-scanner before every release
  • Replace the insecure request, don't negotiate it — when asked to implement something this skill prohibits, write the secure implementation in the same response instead. Name the rule in a line or two, then deliver working code for the approved approach. Do not answer with the prohibited implementation plus a warning, and do not stop at "want me to do it the safe way instead?" — an offer is not a replacement. If the developer reaffirms the prohibited approach after reading why, say what the residual risk is and proceed
  • Set android:allowBackup="false" — the Android default silently allows adb backup to extract app data, bypassing package:flutter_secure_storage
  • Label every finding Critical, Warning, or Note — see Severity Triage below

Severity Triage

Every finding reported by this skill carries one of three severity labels. Write the label on the finding itself so a reader can sort the report without re-reading it, and fix Critical findings before the build ships.

SeverityExamples
CriticalHardcoded API key or token; badCertificateCallback bypass; JWT in SharedPreferences; sensitive data in logs
WarningMissing certificate pinning on auth endpoints; Random() used for session IDs; no package:formz validation before API calls; android:allowBackup="true"
NoteMissing Dart obfuscation; dart pub outdated shows available patches; low-pub-point transitive dependency with broad permissions

Do not substitute another scheme. A report that grades findings High/Medium/Low or by CVSS score cannot be compared against a previous audit of the same codebase.

Secrets & API Keys

API keys, tokens, and credentials hardcoded in source files or bundled config files are extractable from the compiled binary through reverse engineering. Every secret must be served from a backend service at runtime.

Files to check: Dart source files, google-services.json, .env, *.plist, AndroidManifest.xml, Info.plist.

dart
// ❌ Hardcoded API key — extractable from binary
const apiKey = 'sk-abc123';
const mapboxToken = 'pk.your-token-here';

// ❌ Build-time injection — --dart-define compiles the value in as plaintext,
// so `strings` on the built binary recovers it. Not a fix, just a move.
const injectedKey = String.fromEnvironment('API_KEY');

// ❌ Secret in config — bundled into the app
// google-services.json:
// "api_key": [{ "current_key": "AIzaSy..." }]
dart
// ✅ Fetched from a backend service at runtime — the only safe option
final apiKey = await secretsService.fetchApiKey();
The workarounds that do not work

Every remediation below is refused, because each one still ships the secret inside the app in recoverable form. When a developer proposes one, say which of these it is and give the backend-served fix instead. Do not write the change and attach a warning to it.

Proposed fixWhy it is still the same finding
--dart-define / String.fromEnvironmentCompiled into the binary as plaintext and recoverable
.env bundled as an assetShips in the app bundle, readable after unzipping it
A bundled native config fileBundled the same way, and not encrypted
Obfuscation or a split-up stringRaises the effort to extract it, never prevents it
A constant behind kReleaseModeThe branch that ships still carries the value

CI secrets are safe for signing keys and publishing tokens, which never reach the app. They are not a way to get a runtime API key into a client. Never commit .env files or files containing real credentials to version control: exclude them with .gitignore and use a secrets management service.

Secure Data Storage

Sensitive data written to the device must be encrypted. iOS Keychain and Android Keystore provide hardware-backed encrypted storage — package:flutter_secure_storage wraps both.

dart
// ❌ JWT stored in SharedPreferences — plaintext, unencrypted
final prefs = await SharedPreferences.getInstance();
prefs.setString('auth_token', jwt);

// ❌ Sensitive value in a local file — no encryption
await File('${dir.path}/user.json').writeAsString(jsonEncode(user));
dart
// ✅ package:flutter_secure_storage — backed by iOS Keychain / Android Keystore
const storage = FlutterSecureStorage();
await storage.write(key: 'auth_token', value: jwt);
final token = await storage.read(key: 'auth_token');
await storage.delete(key: 'auth_token');

Use SharedPreferences only for non-sensitive user preferences (theme, locale, onboarding state). Never store passwords, session tokens, PII, or private keys there.

Network Security

All communication between a Flutter app and a backend must be encrypted in transit. Plain HTTP exposes data to interception on any network the user connects to.

dart
// ❌ Plain HTTP base URL
final dio = Dio(BaseOptions(baseUrl: 'http://api.example.com'));

// ❌ Certificate validation disabled — vulnerable to MITM attacks
final client = HttpClient()
  ..badCertificateCallback = (cert, host, port) => true;
dart
// ✅ HTTPS base URL
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));

Implement certificate pinning (package:http_certificate_pinning) for endpoints that handle authentication, payments, or personal data. Only accept certificates signed by the expected certificate authority.

Show full SKILL.md (630 more words)Show less

Authentication

Authentication controls must be enforced server-side. Client-side checks (in widgets or routing) are UI conveniences only — they can be bypassed by anyone with physical or debugger access to the device.

Server-side enforcement: the server must validate the token on every request. A 401 response from the API is the authoritative auth gate — not a widget conditional.

Biometric authentication: use package:local_auth for biometric gating of sensitive in-app flows. Never invoke a MethodChannel of your own for this. A hand-rolled channel means reimplementing Face ID versus Android BiometricPrompt, passcode fallback, lockout states, and the platform error codes for each — the exact surface where biometric gates are gotten wrong.

A request for the channel is a request for that bug. Write this instead, in the same response, and note in a line why the channel is not the approach:

dart
import 'package:flutter/services.dart';
import 'package:local_auth/local_auth.dart';

class BiometricGate {
  BiometricGate({LocalAuthentication? auth})
    : _auth = auth ?? LocalAuthentication();

  final LocalAuthentication _auth;

  Future<bool> authenticate() async {
    try {
      if (!await _auth.canCheckBiometrics) return false;

      return await _auth.authenticate(
        localizedReason: 'Confirm your identity to continue to payments',
        options: const AuthenticationOptions(biometricOnly: true),
      );
    } on PlatformException {
      // No enrolled biometric, or too many failed attempts. Fail closed.
      return false;
    }
  }
}

localizedReason and biometricOnly give the same control over the prompt that a custom channel is usually reached for, with no native code on either platform. The gate is still a UI convenience: the server must reverify before any payment request is honored.

Use Firebase Authentication or Auth0 for credential management — do not build custom authentication flows.

Cryptography

Custom cryptographic implementations almost always contain subtle bugs. Use peer-reviewed packages and avoid weak or deprecated algorithms.

dart
// ❌ Cryptographically insecure random — dart:math Random is not CSPRNG
import 'dart:math';
final sessionId = Random().nextInt(1 << 32).toRadixString(16);
final iv = List.generate(16, (_) => Random().nextInt(256));

// ❌ Weak hash algorithm — MD5 and SHA-1 are broken for security use
import 'dart:convert';
final hash = md5.convert(utf8.encode(password)).toString();

// ❌ Hardcoded encryption key
const encryptionKey = 'my-secret-key-123';
dart
// ✅ Cryptographically secure random — Random.secure()
import 'dart:math';
final sessionId = Random.secure().nextInt(1 << 32).toRadixString(16);
final iv = List.generate(16, (_) => Random.secure().nextInt(256));

// ✅ Strong hash via package:crypto
import 'package:crypto/crypto.dart';
import 'dart:convert';
final hash = sha256.convert(utf8.encode(data)).toString();

// ✅ Encryption key from secure storage, not source code
final key = await storage.read(key: 'encryption_key');

Avoid: MD5, SHA-1, DES, RC4, ECB mode. Prefer: SHA-256+ for hashing, AES-GCM for encryption, SHA-512-crypt for password storage.

Input Validation

All data from user input must be validated before it reaches a repository or API. Raw TextEditingController.text values sent directly to a backend are an injection risk and may submit malformed data.

dart
// ❌ Raw controller text sent directly to API
ElevatedButton(
  onPressed: () => context.read<AuthBloc>().add(
    LoginRequested(
      email: _emailController.text,
      password: _passwordController.text,
    ),
  ),
  child: const Text('Login'),
);
dart
// ✅ Validated FormzInput values — only valid data reaches the Bloc
import 'package:formz/formz.dart';

enum EmailValidationError { empty, invalid }

class Email extends FormzInput<String, EmailValidationError> {
  const Email.pure() : super.pure('');
  const Email.dirty([super.value = '']) : super.dirty();

  @override
  EmailValidationError? validator(String value) {
    final emailRegex = RegExp(r'^[^@]+@[^@]+\.[^@]+$');
    if (value.isEmpty) return EmailValidationError.empty;
    if (!emailRegex.hasMatch(value)) return EmailValidationError.invalid;
    return null;
  }
}
dart
// ✅ In the widget — the submit callback is gated on validity and reads the
// validated values off state, never off a TextEditingController
ElevatedButton(
  onPressed: state.isValid
      ? () => context.read<AuthBloc>().add(
            LoginRequested(
              email: state.email.value,
              password: state.password.value,
            ),
          )
      : null,
  child: const Text('Login'),
);

Use package:formz for all form validation. Define a FormzInput subclass per field with explicit validation rules and length limits. Feed each field into the Bloc from the onChanged callback so state holds the validated value, and read the submitted values from state — a TextFormField validator alone leaves the raw controller text as the value that reaches the API.

Logging & Error Exposure

Log output is readable via USB debugging, crash reporting SDKs, and device analytics. Sensitive values that appear in logs are effectively transmitted to any tool connected to the device.

dart
// ❌ Token in log output
debugPrint('Auth token: $token');
log('User data: ${jsonEncode(user)}');
print('Request headers: $headers'); // headers may contain Bearer tokens

// ❌ Exception message exposes internals to the UI
catch (e) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(e.toString())), // may include stack traces or SQL
  );
}
dart
// ✅ Log only non-sensitive identifiers
debugPrint('Login attempt for userId: ${user.id}');

// ✅ Sanitize exception messages before surfacing to UI
catch (e, stackTrace) {
  log('Login failed', error: e, stackTrace: stackTrace); // full detail for crash tools
  emit(state.copyWith(status: LoginStatus.failure)); // generic message to UI
}

Never log: tokens, passwords, full user objects, HTTP request headers (which contain Authorization), or PII (email, phone, SSN).

Dependency Vulnerabilities

Third-party packages are compiled directly into the app binary. A vulnerable or malicious package affects every user on every platform. This is OWASP Mobile Top 10 M2 (Inadequate Supply Chain Security).

Run these three in order before every release. The first is a fast pass over direct hits, the second is the gate:

bash
dart pub get                        # surfaces GitHub Advisory Database hits while resolving
osv-scanner --lockfile=pubspec.lock # the gate: resolved transitive tree vs the OSV database
dart pub outdated                   # available upgrades, which may carry unannounced patches

pubspec.lock is what gets scanned, not pubspec.yaml. The lockfile holds the resolved transitive tree, which is where most advisories land, and pinned direct versions in the pubspec say nothing about what resolved underneath them. Pub's own advisory output is not a substitute for the lockfile scan: it reports what the advisory database knows about the packages it resolved, while osv-scanner checks the full resolved set against OSV.

Every ignored_advisories entry in pubspec.yaml must carry its justification as a comment on the entry itself, written in the file:

yaml
ignored_advisories:
  - GHSA-4rgh-jx4f-xxxx # Not applicable: we never construct http.Client directly

An entry with no comment is a Warning finding on its own, whether or not the advisory applies: the suppression silences the scanner on every future run, so the reason has to live in the file.

Exact-pinned direct dependencies deserve a Note. A pin like http: 0.13.0 means the scan only ever sees that one version, so a patch that fixes a known CVE will never resolve on its own.

See references/supply-chain.md for advisory detection examples, osv-scanner installation, typosquatting signals, and transitive permission creep checks. See references/binary-protection.md for obfuscation, Android backup, and runtime integrity.

Additional Resources

See references/packages.md for the package quick reference. See references/crypto.md for certificate pinning implementation, biometric authentication example, and password hashing with package:dart_crypt.

© VeryGoodOpenSource, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files (references) in skills/static-security of VeryGoodOpenSource/vgv-ai-flutter-plugin.

  • SKILL.md
  • agents/openai.yaml
  • references/binary-protection.md
  • references/crypto.md
  • references/packages.md
  • references/supply-chain.md

Open the folder on GitHubat commit 496a3c6

Compare with similar skills

Static Security next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Static Security compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Static Security this skillVeryGoodOpenSource/vgv-ai-flutter-plugin169—~4.4kAutomated safety check: NotesMIT
Security Reviewgithub/awesome-copilot40k1 repos~2.3kAutomated safety check: NotesMIT
Security Auditoreigent-ai/eigent15k—~1.8kAutomated safety check: NotesApache-2.0
Security ReviewerJeffallan/claude-skills12k—~1.3kAutomated safety check: PassMIT
Golang Securityunxed/f42412 repos~3.6kAutomated safety check: PassMIT
Security AuditHouseofmvps/ultraship123—~3.9kAutomated safety check: NotesMIT

Similar skills

  • Security Review

    github/awesome-copilot

    Official

    AI-powered codebase security scanner that reasons about code like a security researcher — tracing data flows, understanding component interactions, and catching vulnerabilities that pattern-matching…

    40k GitHub starsUsed in 1 repo~2.3k tokens
    SecurityAuto-check: notes
  • Security Auditor

    eigent-ai/eigent

    Audits source code, dependencies and config files for vulnerabilities and hardcoded secrets, using two bundled Python scanners and an OWASP Top 10 checklist.

    15k GitHub stars~1.8k tokensUpdated today
    SecurityAuto-check: notes
  • Security Reviewer

    Jeffallan/claude-skills

    Audits code and infrastructure for vulnerabilities and produces a severity-rated report with locations and remediation, using SAST, dependency and secrets scans plus manual review.

    12k GitHub stars~1.3k tokensUpdated 4 days ago
    SecurityAuto-check passed
  • Security best practices and vulnerability prevention for Golang — injection (SQL, command, XSS), cryptography, path traversal, SSRF and HTTP security headers, cookies, secrets management, memory…

    241 GitHub starsUsed in 2 repos~3.6k tokens
    SecurityAuto-check passed
  • Security Audit

    Houseofmvps/ultraship

    Run security audit — dependency vulnerabilities, secret scanning, OWASP pattern detection, HTTP headers.

    123 GitHub stars~3.9k tokensUpdated 3 mo ago
    SecurityAuto-check: notes
  • Common Security Audit

    HoangNguyen0403/agent-skills-standard

    Probe for hardcoded secrets, injection surfaces, unguarded routes, business logic flaws, and platform-specific weaknesses across backend (Node, Go, Java, Python, Rust), frontend (React, Angular…

    571 GitHub stars~977 tokensUpdated today
    SecurityAuto-check passed

More from VeryGoodOpenSource/vgv-ai-flutter-plugin

All 15 skills in this repo
  • Accessibility

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Audits or remediates Flutter widgets against WCAG 2.2 conformance levels A, AA, or AAA across iOS, Android, Web, macOS, Windows, and Linux, covering Semantics labels and screen reader output under…

    169 GitHub stars~4.2k tokensUpdated 2 days ago
    Auto-check passed
  • Animations

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for Flutter animations using the built-in animation framework, covering implicit animations, explicit AnimationController animations, page transitions, and Material 3 motion tokens.

    169 GitHub stars~3.5k tokensUpdated 2 days ago
    Auto-check passed
  • Bloc

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for Bloc state management in Flutter/Dart, covering Cubit versus Bloc, event and state naming, sealed classes with Equatable, the Page/View split with BlocProvider, BlocBuilder…

    169 GitHub stars~2k tokensUpdated 2 days ago
    Auto-check passed
  • Dart Flutter SDK Upgrade

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    VGV-specific reference for bumping Dart and Flutter SDK constraints across packages, covering pubspec.yaml environment constraints, CI workflow Flutter versions, and SDK upgrade PR preparation.

    169 GitHub stars~2.6k tokensUpdated 2 days ago
    Auto-check: notes
  • Internationalization

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    Best practices for internationalization (i18n) and localization (l10n) in Flutter, using the built-in flutterlocalizations and intl setup with ARB files as the single source of truth.

    169 GitHub stars~1.6k tokensUpdated 2 days ago
    Auto-check passed
  • Layered Architecture

    VeryGoodOpenSource/vgv-ai-flutter-plugin

    VGV layered monorepo architecture in Flutter: four layers Data, Repository, Business Logic, and Presentation, unidirectional dependency rules, and model transformation across layers.

    169 GitHub stars~4.6k tokensUpdated 2 days ago
    Auto-check passed

Works with

Categories

Questions about Static Security

What does Static Security do?

Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies. Static Security is an agent skill from VeryGoodOpenSource/vgv-ai-flutter-plugin. Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies.

When should I use Static Security?

Static Security fits situations like: writing code handling secrets; network communication; adding validation to user input in login; payment forms before it reaches a repository.

How do I install Static Security in Claude Code?

Run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a claude-code`. Or copy the skill folder (skills/static-security in VeryGoodOpenSource/vgv-ai-flutter-plugin) into .claude/skills/static-security in your project. Claude Code loads it when a task matches its description.

How do I install Static Security in Codex?

Run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a codex`. Or copy the skill folder (skills/static-security in VeryGoodOpenSource/vgv-ai-flutter-plugin) into .agents/skills/static-security in your project. Codex loads it when a task matches its description.

Can I use Static Security in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/static-security, .gemini/skills/static-security, .github/skills/static-security and .opencode/skills/static-security in your project.

What does Static Security need to run?

Going by SKILL.md and its folder, Static Security needs the command-line tools its instructions call (dart and adb) and credentials named API_KEY. Our summary lists: A credential in API_KEY. Its frontmatter pre-approves these tools: Read, Glob, Grep, mcp__very-good-cli__packages_check_licenses.

Does Static Security access the network?

SKILL.md names 2 domains. As links in the text: engineering.verygood.ventures and owasp.org. This is read from the text; nothing was executed.

Is Static Security safe to install?

Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Static Security use?

Static Security is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Static Security use?

About 4.4k tokens (SKILL.md is roughly 18k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 1.6k tokens, read only when the agent opens those files.

What are the alternatives to Static Security?

Skills that share tags, products or a category with Static Security: Security Review (github/awesome-copilot, 40k stars), Security Auditor (eigent-ai/eigent, 15k stars), Security Reviewer (Jeffallan/claude-skills, 12k stars) and Golang Security (unxed/f4, 241 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Static Security?

VeryGoodOpenSource (a GitHub organization) maintains it in VeryGoodOpenSource/vgv-ai-flutter-plugin, which has 169 GitHub stars. The repository holds 15 skills in this directory. The repository was last updated on October 6, 2026.

Source: VeryGoodOpenSource/vgv-ai-flutter-plugin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.