Security Review
github/awesome-copilot
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…
Static security review for Flutter mobile apps and Dart code: hardcoded secrets, insecure storage, unsafe network calls, leaky logs, vulnerable dependencies.
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ 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-srcUse ~/.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/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .claude/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-securityType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/static-security .agents/skills/static-security && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .agents/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/static-security .cursor/skills/static-security && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .cursor/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git --path skills/static-security--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/static-security .gemini/skills/static-security && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .gemini/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-securityInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/static-security .github/skills/static-security && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .github/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install VeryGoodOpenSource/vgv-ai-flutter-plugin static-security --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/static-security .opencode/skills/static-security && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "static-security" agent skill from https://github.com/VeryGoodOpenSource/vgv-ai-flutter-plugin/tree/main/skills/static-security into .opencode/skills/static-security/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "static-security", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
static-securityStatic 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. 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.
Read from SKILL.md and the folder at commit 496a3c6. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
ReadGlobGrepmcp__very-good-cli__packages_check_licensesFrom allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
dartadbFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
engineering.verygood.venturesowasp.orgFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
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.
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.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
--dart-define, String.fromEnvironment, a .env file, or CIneither is `String.fromEnvironment`, a `.env` file, a native config file, an obfuscated constant, or a split-up string.t source files, `google-services.json`, `.env`, `*.plist`, `AndroidManifest.xml`, `Info.plist`.| `.env` bundled as an asset | Ships in the app bundle, readable after unzipping it |ime API key into a client. Never commit `.env` files or files containing real credentials to version control: exclude thAutomated 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.
The full file from VeryGoodOpenSource/vgv-ai-flutter-plugin at commit 496a3c6, republished under its MIT licence (© VeryGoodOpenSource). 1,470 words, ~4,438 tokens.
.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.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.
Apply these standards to all Flutter security work:
--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 runtimepackage:flutter_secure_storage for sensitive on-device data — SharedPreferences is plaintext and unencrypted; never store tokens, PII, or session data thereRandom.secure() for security-sensitive randomness — dart:math's Random() is a pseudo-random number generator, not cryptographically securepackage:crypto or package:dart_cryptprint(), log(), and debugPrint() output is readable on-device and in crash reporting toolspubspec.lock with osv-scanner before every releaseandroid:allowBackup="false" — the Android default silently allows adb backup to extract app data, bypassing package:flutter_secure_storageCritical, Warning, or Note — see Severity Triage belowEvery 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.
| Severity | Examples |
|---|---|
| Critical | Hardcoded API key or token; badCertificateCallback bypass; JWT in SharedPreferences; sensitive data in logs |
| Warning | Missing certificate pinning on auth endpoints; Random() used for session IDs; no package:formz validation before API calls; android:allowBackup="true" |
| Note | Missing 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.
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.
// ❌ 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..." }]// ✅ Fetched from a backend service at runtime — the only safe option
final apiKey = await secretsService.fetchApiKey();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 fix | Why it is still the same finding |
|---|---|
--dart-define / String.fromEnvironment | Compiled into the binary as plaintext and recoverable |
.env bundled as an asset | Ships in the app bundle, readable after unzipping it |
| A bundled native config file | Bundled the same way, and not encrypted |
| Obfuscation or a split-up string | Raises the effort to extract it, never prevents it |
A constant behind kReleaseMode | The 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.
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.
// ❌ 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));// ✅ 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.
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.
// ❌ 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;// ✅ 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.
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:
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.
Custom cryptographic implementations almost always contain subtle bugs. Use peer-reviewed packages and avoid weak or deprecated algorithms.
// ❌ 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';// ✅ 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.
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.
// ❌ Raw controller text sent directly to API
ElevatedButton(
onPressed: () => context.read<AuthBloc>().add(
LoginRequested(
email: _emailController.text,
password: _passwordController.text,
),
),
child: const Text('Login'),
);// ✅ 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;
}
}// ✅ 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.
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.
// ❌ 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
);
}// ✅ 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).
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:
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 patchespubspec.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:
ignored_advisories:
- GHSA-4rgh-jx4f-xxxx # Not applicable: we never construct http.Client directlyAn 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.
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
SKILL.md and 5 other files (references) in skills/static-security of VeryGoodOpenSource/vgv-ai-flutter-plugin.
Open the folder on GitHubat commit 496a3c6
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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Static Security this skillVeryGoodOpenSource/vgv-ai-flutter-plugin | 169 | — | ~4.4k | Automated safety check: Notes | MIT | |
| Security Reviewgithub/awesome-copilot | 40k | 1 repos | ~2.3k | Automated safety check: Notes | MIT | |
| Security Auditoreigent-ai/eigent | 15k | — | ~1.8k | Automated safety check: Notes | Apache-2.0 | |
| Security ReviewerJeffallan/claude-skills | 12k | — | ~1.3k | Automated safety check: Pass | MIT | |
| Golang Securityunxed/f4 | 241 | 2 repos | ~3.6k | Automated safety check: Pass | MIT | |
| Security AuditHouseofmvps/ultraship | 123 | — | ~3.9k | Automated safety check: Notes | MIT |
github/awesome-copilot
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…
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.
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.
unxed/f4
Security best practices and vulnerability prevention for Golang — injection (SQL, command, XSS), cryptography, path traversal, SSRF and HTTP security headers, cookies, secrets management, memory…
Houseofmvps/ultraship
Run security audit — dependency vulnerabilities, secret scanning, OWASP pattern detection, HTTP headers.
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…
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…
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.
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…
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.
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.
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.
Categories
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.