Skip to content
Mobile
Skill

/static-security

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,

BOOST
From plugin
vgv-ai-flutter-plugin
17315 skills1 agent3 hooks2 MCP
Install
$ npx -y skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill static-security --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/static-security

Context preview

The summary Claude sees to decide when to auto-load this skill.

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,

SKILL.md

static-security.SKILL.md
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.
argument-hint: "[file-or-directory]"
allowed-tools: Read Glob Grep mcp__very-good-cli__packages_check_licenses
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](https://engineering.verygood.ventures/general-practices/security_in_mobile_apps/) guide and the [OWASP Mobile Top 10](https://owasp.org/www-project-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.

| 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.

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`.

// ❌ 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');

// ❌ Secr
Read more
Ships withvgv-ai-flutter-plugin

A Claude Code plugin that accelerates Flutter & Dart development with best-practices skills from Very Good Ventures. Developed with 💙 by Very Good Ventures 🦄

Get the whole plugin

Other skills on vgv-ai-flutter-plugin.