From vanguard-frontier-agentic
Reviews Pinia/Vuex state stores for five security defect classes: sensitive data persistence, untrusted hydration, SSR pollution, store plugin vulnerabilities, and devtools exposure.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vanguard-frontier-agentic:vue-state-store-security-reviewThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Review Pinia and legacy Vuex state-store code for the security-critical defect classes that
Review Pinia and legacy Vuex state-store code for the security-critical defect classes that
are specific to state stores as a component — not general Vue architecture, not composable
design, and not SSR hydration/injection issues that belong to vue-ssr-security-review. This
skill exists to keep the review anchored to five documented defect classes: (a) sensitive data
persisted client-side without scoping, (b) store hydration from an untrusted server payload
with un-escaped serialization, (c) SSR store-singleton cross-request pollution, (d) store
plugins/hooks acting on untrusted payloads and client-held flags used as an authorization
source of truth, and (e) devtools state exposure in production. It does not re-litigate
general reactivity/composable architecture, v-html/URL-injection review (covered by
vue-ssr-security-review), or Composition API design quality (covered by
vue-composition-api-architecture-review) in every response.
Use this skill when the user asks to:
defineStore) or a legacy Vuex module/store for security
issues,pinia-plugin-persistedstate / vuex-persistedstate configuration is safe
(what gets persisted, and where),entry-server.js, a Nuxt server plugin, an
Express/Node handler that constructs createPinia()/createStore()) for cross-request
pollution risk,$subscribe/$onAction hook, or Vuex plugin that consumes
mutation/action payloads,isAdmin, role) is being trusted
as an authorization boundary,Do not use this skill for:
v-html/dynamic-URL injection review or SSR entry-point app/router creation — use
vue-ssr-security-review for those; this skill covers the store specifically, not the
broader SSR rendering surface (load both skills together if the review spans both),vue-composition-api-architecture-review instead,state-management-decision-review instead,resolve-library-id before citing any store-behavior claim. This
skill's three grounding libraries: /vuejs/pinia (Pinia core — SSR hydration, plugins,
$subscribe/$onAction), /prazdevs/pinia-plugin-persistedstate (persistence defaults and
pick/storage config), /vuejs/vuex (legacy Vuex — state as function, devtools
option, plugin/module API).query-docs against /prazdevs/pinia-plugin-persistedstate to confirm persistence
defaults before flagging a persistence config: storage defaults to localStorage when
unset; pick (an array of dotted state-path strings) restricts persistence to named paths;
with no pick, the entire state is persisted. Cite these as documentation-based.query-docs against /vuejs/pinia to confirm SSR hydration mechanics before flagging a
hydration finding: the documented client-side pattern is
pinia.state.value = JSON.parse(window.__pinia), and Pinia's own SSR guide states escaping
the serialized state is "VERY important if the content of the state can be changed by
the user, which is almost always the case," recommending devalue (or equivalent) over naive
JSON.stringify. Cite as documentation-based.query-docs against /vuejs/pinia to confirm $subscribe/$onAction hook signatures
(mutation object with type/storeId/payload; action object with name/store/args/
after/onError) before describing a plugin-hook finding — do not invent a hook name or
argument Context7 does not confirm.query-docs against /vuejs/vuex to confirm the state: () => ({...}) factory pattern
(module reusability without shared state) and the devtools: boolean store option before
citing either — do not assume Pinia has an equivalent devtools boolean on defineStore/
createPinia; Context7 does not confirm that API surface for Pinia, so any Pinia-devtools
concern must be scoped to "a build-time devtools plugin explicitly force-enabled in
production," not a Pinia store option, and labeled inference unless a repo-specific config
is found.package.json first to confirm which store library is in play (pinia,
pinia-plugin-persistedstate, vuex, vuex-persistedstate) and its major version — API
names and defaults differ between Pinia and Vuex and across Vuex 3/4; do not apply one
library's API names to the other.official_docs URLs in this skill's
metadata.json and label the claim documentation-based, unverified against current release.persist/pick/storage config, the specific module-scope createPinia()/createStore()
declaration, or the specific untraced payload sink is not a valid finding — it is a guess.state() shape and the full persist
config together. A persist: true (or persist: {}) with no pick/paths array persists
the entire state — treat every sensitive field in that state as persisted unless a pick
list demonstrably excludes it. A pick list that omits the sensitive field(s) clears the
finding for those fields specifically (not for the whole store, if other sensitive fields
remain unscoped).vue-ssr-security-review requires for app instances: is the createPinia()/
createStore() call inside the per-request handler, and does that handler close over any
module-scope mutable/reactive reference? An immutable module-scope constant (a frozen config
object, a static route table) is not the risk; a store instance or mutable cache is.isAdmin, role, permissions) as an
authorization boundary for a mutating action unless the review also confirms (via visible
server-side code, or an explicit statement that server-side authorization is out of scope for
this static review) that the actual mutation is re-checked server-side. A store flag gating
only UI visibility (hiding a button) is not itself a finding; a store flag gating whether a
mutating network call is made is a finding regardless of UI-layer intent, because the flag
is client-writable.$subscribe/$onAction/Vuex-plugin hook as risky. Only hooks that act on
the payload with a side effect (write, external call, log of sensitive data, mutate another
store) and lack payload validation are findings; read-only observation (e.g., analytics event
naming) is not.Load these only when needed:
pinia-plugin-persistedstate/vuex-persistedstate configuration, SSR store
creation/singleton risk, or server-payload hydration (window.__pinia/__INITIAL_STATE__).$subscribe/$onAction/Vuex-plugin hooks, client-held role/permission
flags used for access control, or devtools production exposure.Return, at minimum:
persistence, hydration,
ssr-pollution, untrusted-payload, client-auth-flag, or devtools-exposure), the
concrete data-flow trace (state field → persist config, or server payload → hydration call,
or module-scope declaration → per-request reachability, or payload → sink), and a fix sketch
matching the grounding library's documented pattern,pick/paths (if any) and which are not,repo evidence, documentation-based, or inference), with
structural risk findings explicitly labeled as structural risk, not as confirmed-exploited,vue-ssr-security-review").npx claudepluginhub raishin/vanguard-frontier-agentic --plugin vanguard-frontier-agenticGuides Pinia state management in Vue apps: defining stores, state/getters/actions, plugins, composables, testing, SSR, Nuxt, HMR.
Guides using Pinia for Vue state management: defining stores, state/getters/actions, plugins, SSR, Nuxt integration, and testing with @pinia/testing.
Guides Pinia v3 setup for Vue 3 state management with defineStore, getters, actions, option/setup syntaxes, Nuxt SSR, Vuex migration, hydration, and testing.